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

Aaron K Saunders - Mar 10 '21 - - Dev Community

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>
Enter fullscreen mode Exit fullscreen mode

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: { ... }
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
    };
  }
});
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
    };
  }
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

GitHub logo aaronksaunders / ionic-vue-nav-in-modals

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






๐Ÿ’ฅ Additional Content

๐Ÿ’ฅ Social Media

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .