How to Navigate in Ionic Modals with ion-nav in VueJS
Tags: ionic, vue, tutorial, webdev
Published: 2021-03-10 05:11:11

### Overview
The idea here is to show how to create a navigation stack in your [Ionic VueJS Application](https://ionicframework.com/docs/vue/overview) 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

<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1615266373274/GtZX5udMK.gif"/>

**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.

{% youtube kJLu2Vt0H2A %}

### 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**
```html
<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.

```javascript
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**
```html
<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`](https://v3.vuejs.org/guide/composition-api-provide-inject.html#scenario-background) 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


```javascript
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.

```javascript
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](https://www.youtube.com/channel/UCMCcqbJpyL3LAv3PJeYz2bg) I have generated on my channel

{% github aaronksaunders/ionic-vue-nav-in-modals %}


#### 💥 Additional Content
- 🎓 Udemy Courses - https://www.udemy.com/user/aaronsaunders/
- 🎓 Gumroad Courses/Content - https://www.gumroad.com/fiwic

#### 💥 Social Media 
- [YouTube Channel, With Over 150 videos on Ionic Framework](https://www.youtube.com/channel/UCMCcqbJpyL3LAv3PJeYz2bg)
- Twitter - https://twitter.com/aaronksaunders
- Facebook - https://www.facebook.com/ClearlyInnovativeInc
- Instagram - https://www.instagram.com/aaronksaunders/
- Devto - https://dev.to/aaronksaunders
- 🌐 www.fiwic.com