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
- IonModal - https://ionicframework.com/docs/api/modal
- IonNav - https://ionicframework.com/docs/api/nav > The IonNav - is a standalone component for loading arbitrary components and pushing new components onto the stack.
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 withprovide
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 onion-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
- 🎓 Udemy Courses - https://www.udemy.com/user/aaronsaunders/
- 🎓 Gumroad Courses/Content - https://www.gumroad.com/fiwic