How to Navigate in Ionic Modals with ion-nav in VueJS

How to Navigate in Ionic Modals with ion-nav in VueJS

ยท

9 min read

Overview

The idea here is to show how to create a navigation stack in your Ionic VueJS Application that is specifically for a modal dialog. The modal dialog will still be working with pages, pushing and popping onto the navigation stack and the changes will not impact the overall application navigation.

Source code available at the end of the blog post, I have edited out imports to keep the code concise

Ionic Documentation Used

Home Component

The top-level container for the application, the primary objective of this component is to open the modal to kick things off. I have emptied out the blank template generated from the @ionic-cli to get the project started.

The code for rendering and managing the hiding and showing of the modal is directly from the Ionic documentation linked above. We create a reactive variable, isOpenRef, in the component that determines if the modal is visible or not.

Home.vue

<ion-content :fullscreen="true" class="ion-padding">
  <ion-button @click="setOpen(true)">Show Modal With Nav</ion-button>
  <ion-modal
    :is-open="isOpenRef"
    @onDidDismiss="setOpen(false)"
  >
    <base-modal :rootPage="ModalHome"></base-modal>
  </ion-modal>
</ion-content>

Below is the javascript code to open the modal and also notice we import the rootPage component, ModalHome, that will be used in the template.

You will need to import the component, but it does not need to be added to the components section of the file, but you do need to return it from the setup function so the template can access the value.

import { ... } from "@ionic/vue";
import { defineComponent, ref } from "vue";
import BaseModal from "./BaseModal.vue";

// root page component defined here
import ModalHome from "./ModalHome.vue";


export default defineComponent({
  name: "Home",
  setup() {
    const isOpenRef = ref(false);
    const setOpen = (state: boolean) => (isOpenRef.value = state);
    return { isOpenRef, setOpen,  ModalHome };
  },
  components: { ... }
});

BaseModal Component

The container for the modal navigation stack within the application

The BaseModal is the container for all of the navigation that we are going to be doing in the modal. The BaseModal is rendered in the Home component.

The rootPage is assigned when the modal is displayed and the ion-nav is used to render the pages and the navigation as we move around in different documents inside of the modal.

notice that I have set the modal-nav id so that I can query the document to get the component to make the appropriate API calls.

BaseModal.vue

<template>
  <div>
    <ion-nav :root="rootPage" id="modal-nav"></ion-nav>
  </div>
</template>

<script>
import { defineComponent } from "vue";
import { IonNav } from "@ionic/vue";
export default defineComponent({
  name: "BaseModal",
  components: {
    IonNav
  },
  props: ["rootPage"],
});
</script>

ModalHome Component

The rootPage in the modal navigation stack

ModalHome.vue

<ion-page>
  <ion-header :translucent="true">
    <ion-toolbar>
      <ion-buttons slot="end">
        <ion-button @click="closeModal">CLOSE</ion-button>
      </ion-buttons>
      <ion-title>MODAL HOME</ion-title>
    </ion-toolbar>
  </ion-header>
  <ion-content class="ion-padding">
    <h2>MODAL HOME</h2>
    <ion-button @click="nextPage">SHOW MODAL DETAIL</ion-button>
  </ion-content>
</ion-page>

Call document.getElementById to get the ion-nav when the component is mounted. We need to import the next page that we want to push ModalHomeDetailVue Pass properties to the next component as a object when calling push method on ion-nav.

I did investigate using provide/inject to get the ModalNav and save it with provide so that any component in the modal navigation stack can access it; but I wanted to keep this example as basic as possible and focused on ion-nav

Import the modalController from @ionic/vue so we can close the modal completely and return to the default application navigation stack

import { defineComponent, ref, onMounted } from "vue";
import { ... } from "@ionic/vue";

// the detail page
import ModalHomeDetailVue from "./ModalHomeDetail.vue";

export default defineComponent({
  name: "ModalHome",
  components: { ... },
  setup() {
    // the nav ref
    const modalNav = ref(null);

    // get the the ion-nav element so we can make
    // api calls using ion-nav
    onMounted(() => {
      const v = document.getElementById("modal-nav");
      modalNav.value = v;
    });

    /**
     *  when going to the next page, I pass the nav as a property
     * so I don't need to get it from the document again
     */
    const nextPage = () => {
      modalNav.value.push(ModalHomeDetailVue, {
        // these come across as properties on the component
        modalNav: modalNav
      });
    };

    /**
     * close the modal dialog
     */
    const closeModal = async () => {
      await modalController.dismiss();
    };

    return {
      nextPage,
      closeModal
    };
  }
});

ModalHomeDetail Component

The first page pushed in the modal navigation stack. In this component, we demonstrate how we handle the back navigation and passing properties to pages/components as we push them onto the stack using ion-nav

ModalHomeDetail.vue

<ion-page>
  <ion-header :translucent="true">
    <ion-toolbar>
      <ion-buttons slot="start">
        <ion-button @click="goBack">BACK</ion-button>
      </ion-buttons>
      <ion-title>MODAL HOME DETAIL</ion-title>
    </ion-toolbar>
  </ion-header>
  <ion-content class="ion-padding">
    <h2>MODAL HOME DETAIL</h2>
  </ion-content>
</ion-page>

From what I can determine we need to handle the back butt ourselves, so I have added a function in the component to handle that by calling nav.pop(). We get the ion-nav because it was passed in as a component property.

import { defineComponent } from "vue";
import { ... } from "@ionic/vue";
export default defineComponent({
  name: "ModalHomeDetail",
  components: { ... },
  props: [ "modalNav"],
  setup(props) {
    /**
     * get the nav from the props and go back
     */
    const goBack = () => {
      const nav = props.modalNav.value;
      nav.pop();
    };
    return {
      goBack
    };
  }
});

Test On Device

I have a mac so that is what most of my work is based on; if you run into issues on android, leave a comment or post an issue in the github repo and I will get back to you.

ionic build
ionic cap add android
ionic cap add ios
ionic cap run ios --livereload

Source Code

Full project source code is available in my github repo along with an assortment of other Ionic VueJS and ReactJS content. Please take a look and leave a comment. Also many of the projects are related to YouTube content I have generated on my channel

๐Ÿ’ฅ Additional Content


๐Ÿ’ฅ Social Media


ย