useIonModal: Passing multiple values

I want to use IonModal to capture various inputs and then pass it back to the parent page in React. I’ve been able to get one value to go over but not multiple. I’ve search this forum and other sites with no luck.

It seems that onDismiss below is looking for a string instead of type ModalInput which contains the two values I need to pass back to the parent.

Any help would be appreciated.

            <IonButton
              onClick={() => {
                onDismiss(addedCampaign, "confirm"); //looking for string instead of ModalInput type
              }}
              strong={true}
            >
              Confirm
            </IonButton>

==> Full code below <==

VolCampaignList.tsx

import {
  IonItem,
  IonCol,
  IonGrid,
  IonRow,
  IonCard,
  IonCardContent,
  IonFab,
  IonFabButton,
  IonIcon,
  useIonModal,
} from "@ionic/react";

import { useEffect, useState } from "react";
import { db } from "../../hooks/firebase";
import {
  onSnapshot,
  query,
  collection,
  where,
  orderBy,
} from "firebase/firestore";

import {
  VolCampaignsData,
  toVolCampaignsData,
} from "../../models/models4Campaigns";
import { RolesData, toRole } from "../../models/models4Roles";
import { CampaignsData, toCampaignsData } from "../../models/models4Campaigns";
import { mapRole, mapCampaign } from "../../utils/lookups";
import { addCircle, addCircleOutline } from "ionicons/icons";
import VolCampaignModal from "./VolCampaignModal";
import { OverlayEventDetail } from "@ionic/core/components";

import "./VolCampaignList.css";

interface RouteParams {
  id: string;
}

interface ModalInputs {
  campaignId?: string | null;
  roleId?: string | null;
}

const VolCampaignList: React.FC<RouteParams> = ({ id }) => {
  const [campaignsList, setCampaignsList] = useState<VolCampaignsData[]>([]);
  const [allRoles, setAllRoles] = useState<RolesData[]>([]);
  const [allCampaigns, setAllCampaigns] = useState<CampaignsData[]>([]);
  const [addedCampaign, setAddedCampaign] = useState<ModalInputs>();

  const [present, dismiss] = useIonModal(VolCampaignModal, {
    onDismiss: (data: ModalInputs, button: string) => dismiss(data, button),
  });

  useEffect(() => {
    const ref = query(
      collection(db, "campaignsByVolunteers"),
      where("volunteer", "==", id)
    );
    return onSnapshot(ref, ({ docs }) => {
      setCampaignsList(docs.map(toVolCampaignsData));
    });
  }, [id]);

  useEffect(() => {
    const rolesRef = query(collection(db, "roles"), orderBy("role"));
    return onSnapshot(rolesRef, ({ docs }) => {
      setAllRoles(docs.map(toRole));
    });
  }, []);

  useEffect(() => {
    const campaignsRef = query(
      collection(db, "campaigns"),
      orderBy("year", "desc")
    );
    return onSnapshot(campaignsRef, ({ docs }) => {
      setAllCampaigns(docs.map(toCampaignsData));
    });
  }, []);

  const openModal = () => {
    present({
      onWillDismiss: (ev: CustomEvent<OverlayEventDetail>) => {
        if (ev.detail.role === "confirm") {
          console.log(`Hello, ${ev.detail.data}!`);
        }
        console.log(ev.detail.data);
      },
    });
  };

  const addFabButton = () => {
    return (
      <>
        <IonFab slot="fixed" vertical="top" horizontal="end">
          <IonFabButton
            onClick={() => {
              openModal();
            }}
          >
            <IonIcon ios={addCircleOutline} md={addCircle} />
          </IonFabButton>
        </IonFab>
      </>
    );
  };

  return (
    <IonCard>
      <IonCardContent>
        {addFabButton()}
        <IonGrid fixed={true}>
          <IonRow className="vcamp-col-header">
            <IonCol size="6">Campaign</IonCol>
            <IonCol size="6">Role</IonCol>
          </IonRow>
        </IonGrid>
        <IonGrid fixed={true}>
          {campaignsList.map((campaign) => (
            <IonItem button key={campaign.id}>
              <IonRow className="vcamp-data">
                <IonCol size="6">
                  {mapCampaign(campaign.campaign, allCampaigns)}
                </IonCol>
                <IonCol size="6">{mapRole(campaign.role, allRoles)}</IonCol>
              </IonRow>
            </IonItem>
          ))}
        </IonGrid>
      </IonCardContent>
    </IonCard>
  );
};
export default VolCampaignList;

VolCampaignModal.tsx

import { useState, useEffect } from "react";
import {
  IonButtons,
  IonButton,
  IonHeader,
  IonContent,
  IonToolbar,
  IonTitle,
  IonItem,
  IonPage,
  IonSelect,
  IonSelectOption,
} from "@ionic/react";

import { db } from "../../hooks/firebase";
import {
  onSnapshot,
  query,
  collection,
  where,
  orderBy,
} from "firebase/firestore";

import { RolesData, toRole } from "../../models/models4Roles";
import { CampaignsData, toCampaignsData } from "../../models/models4Campaigns";

import "./VolunteersEdit.css";

interface ModalInputs {
  campaignId?: string | null;
  roleId?: string | null;
}

export const VolCampaignModal = ({
  onDismiss,
}: {
  onDismiss: (
    campaignId?: string | null | undefined,
    roleId?: string | null | undefined,
    button?: string
  ) => void;
}) => {
  const [activeRoles, setActiveRoles] = useState<RolesData[]>([]);
  const [activeCampaigns, setActiveCampaigns] = useState<CampaignsData[]>([]);
  const [addedCampaign, setAddedCampaign] = useState<ModalInputs>();

  // const inputRef = useRef<HTMLIonInputElement>(null);

  useEffect(() => {
    const rolesRef = query(
      collection(db, "roles"),
      where("active", "==", true),
      orderBy("role")
    );
    return onSnapshot(rolesRef, ({ docs }) => {
      setActiveRoles(docs.map(toRole));
    });
  }, []);

  useEffect(() => {
    const campaignsRef = query(
      collection(db, "campaigns"),
      where("active", "==", true),
      orderBy("year", "desc")
    );
    return onSnapshot(campaignsRef, ({ docs }) => {
      setActiveCampaigns(docs.map(toCampaignsData));
    });
  }, []);

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonButtons slot="start">
            <IonButton color="medium" onClick={() => onDismiss(null, "cancel")}>
              Cancel
            </IonButton>
          </IonButtons>
          <IonTitle>Campaign Addition</IonTitle>
          <IonButtons slot="end">
            <IonButton
              onClick={() => {
                onDismiss(addedCampaign, "confirm"); //looking for string instead of ModalInput type
              }}
              strong={true}
            >
              Confirm
            </IonButton>
          </IonButtons>
        </IonToolbar>
      </IonHeader>
      <IonContent className="ion-padding">
        <IonItem key="selection-campaign">
          <IonSelect
            label="Campaign"
            placeholder="Make a Selection"
            onIonChange={(event) => {
              setAddedCampaign({
                ...addedCampaign,
                campaignId: event.detail.value,
              });
            }}
          >
            {activeCampaigns.map((campaign) => (
              <IonSelectOption key={campaign.id} value={campaign.id}>
                {campaign.year + " - " + campaign.event}
              </IonSelectOption>
            ))}
            ;
          </IonSelect>
        </IonItem>
        <IonItem key="selection-role">
          <IonSelect
            label="Role"
            placeholder="Make a Selection"
            onIonChange={(event) => {
              setAddedCampaign({
                ...addedCampaign,
                roleId: event.detail.value,
              });
            }}
          >
            {activeRoles.map((role) => (
              <IonSelectOption key={role.id} value={role.id}>
                {role.role}
              </IonSelectOption>
            ))}
            ;
          </IonSelect>
        </IonItem>
      </IonContent>
    </IonPage>
  );
};
export default VolCampaignModal;

Could you just pass back an object containing everything you need?

That is what I was trying to do with addCampaign but I get an error that it is expecting a string instead of the object.

Found the solution on a great YouTube video created by Aaron Saunders.

Ionic Framework ReactJS Modal Tutorial

1 Like