Ionic Modal In Vue JS, Managing Events

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

This post is kinda old, there is a full example on using IonModal Here No TS Ionic Vue Example If you have issues let me know.

-

The Ionic Components forVueJS are still in beta, but I have been using them for a while now and occasionally go back and update some of the samples I have posted in my github repo. Recently I was asked about handling modals, callbacks. I am going to quickly cover all of those in this blog post.

See Video

Setting Up The Parent Component App to Call Modal

<template>
  <ion-app>
    <ion-page>
      <ion-header>
        <ion-toolbar color="primary">
          <ion-title>Modal Test App</ion-title>
        </ion-toolbar>
      </ion-header>
      <ion-content padding>
        <ion-button @click="openModal">Show Modal</ion-button>
      </ion-content>
    </ion-page>
  </ion-app>
</template>
Enter fullscreen mode Exit fullscreen mode

first we import the modal component

import SimpleModal from "./components/SimpleModal.vue";
Enter fullscreen mode Exit fullscreen mode

Inside the script tag for our page, in the methods, section we create a modalCloseHandler method that will be called when the modal is closed.

modalCloseHandler(_value) {
   console.log("modal-closed", _value);

   if (_value.success) {
      // only on success
      alert(JSON.stringify(_value.noteInfo, null, 2));
   }
}
Enter fullscreen mode Exit fullscreen mode

then we have the function openModal that will actually open the modal. In this example I am passing in a property timeStamp just as a way to show how properties are passed into the component when using Ionic.

We next call modal.present() to actually show the modal.

Then finally wait for a response with modal.onDidDismiss()

We need to handle the scenario where the user clicks the backdrop to exit the modal; in that situation we do not want to process the response.

async openModal() {
   let modal = await this.$ionic.modalController.create({
      component: SimpleModal,
         componentProps: {
            propsData: {
               timeStamp: new Date()
            }
         }
      });

   // show the modal
   await modal.present();

   // wait for a response when closing the modal
   let modalResponse = await modal.onDidDismiss();

   // when dismissed by backdrop click, data is undefined,
   // we only process a response from the user behavior
   modalResponse.data && this.modalCloseHandler({...modalResponse.data})
}
Enter fullscreen mode Exit fullscreen mode

This is the complete <script> section of the App component

import SimpleModal from "./components/SimpleModal.vue";

export default {
  name: "App",
  components: {},
  methods: {
    /**
     * called when the modal is closed
     */
    modalCloseHandler(_value) {
      console.log("modal-closed", _value);

      if (_value.success) {
        // only on success
        alert(JSON.stringify(_value.noteInfo, null, 2));
      }
    },
    /**
     * when the user clicks button, we open the modal
     */
    async openModal() {
      let modal = await this.$ionic.modalController.create({
        component: SimpleModal,
        componentProps: {
          parent: this,
          propsData: {
            timeStamp: new Date()
          }
        }
      });

      // show the modal
      await modal.present();

      // wait to see if i get a response
      let modalResponse = await modal.onDidDismiss();

      // when dismissed by clicking outside of modal,
      // data is undefined so we do not handle it
      modalResponse.data && this.modalCloseHandler({...modalResponse.data})
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

The Modal Component - SimpleModal

Please note that the input elements are specific to vue; We are using the vue specific input elements ion-input-vue and ion-textarea-vue

We handle the button click events by calling modalClose(true) when user wants to save the data and modalClose(false) when user clicks cancel

<template>
  <div>
    <ion-header>
      <ion-toolbar>
        <ion-title>Note Modal</ion-title>
      </ion-toolbar>
    </ion-header>
    <ion-content padding>
      <ion-item>
        <ion-label color="primary" position="floating">Title</ion-label>
        <ion-input-vue
          type="text"
          name="title"
          placeholder="Title for note..."
          v-model="noteInfo.title"
        ></ion-input-vue>
      </ion-item>

      <ion-item>
        <ion-label color="primary" position="floating">Description</ion-label>
        <ion-textarea-vue rows="5" placeholder="Note description" v-model="noteInfo.description"></ion-textarea-vue>
      </ion-item>

      <ion-item style="font-size:smaller; text-align: center" lines="none">
        <ion-label>{{(timeStamp +"").split('(')[0]}}</ion-label>
      </ion-item>
      <ion-row>
        <ion-col>
          <ion-button expand="block" @click="modalClose(true)">Save Note</ion-button>
        </ion-col>
        <ion-col>
          <ion-button expand="block" color="danger" @click="modalClose(false)">Cancel</ion-button>
        </ion-col>
      </ion-row>
    </ion-content>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Inside the code/ script tag section of the component be sure to specify the properties that are being passed into the component; in this case it is just the timeStamp

export default {
  name: "SimpleModal",
  props: ["timeStamp"],
  methods: {}
}
Enter fullscreen mode Exit fullscreen mode

We specify the data fields for the form we are working with in the data section of the modal component.

  data() {
    return {
      noteInfo: {
        title: "",
        description: ""
      }
    };
  }
Enter fullscreen mode Exit fullscreen mode

And finally the modalClose function in the methods section. Here we return the data from the form if success is true otherwise we return null.

to pass the information back to the parent onDismiss listener, we access the controller this.$ionic.modalController and call the dismiss method passing the response data as the parameter.

methods: {
  modalClose: function(success) {
    let response = {
      success,
      noteInfo: success ? this.noteInfo : null
    };
    this.$ionic.modalController.dismiss(response);
  }
},
Enter fullscreen mode Exit fullscreen mode

This is the complete <script> section of the SimpleModal component

export default {
  name: "SimpleModal",
  props: ["timeStamp"],
  methods: {
    modalClose: function(success) {
      let response = {
        success,
        noteInfo: success ? this.noteInfo : null
      };
      this.$ionic.modalController.dismiss(response);
    }
  },
  data() {
    return {
      noteInfo: {
        title: "",
        description: ""
      }
    };
  }
};
Enter fullscreen mode Exit fullscreen mode

Using Vue Event Emitters

Here we are building off of the previous section where we demonstrated how to use a modal form to present information in a vuejs application using Ionic Framework Components.

More information on Custom Events: https://vuejs.org/v2/guide/components-custom-events.html

In this example, we will show how to use standard vue $emit to get a similar result. This is also an approach for managing events from the Modal component other than actually closing the modal.

Setting Up App Component

The the App component lifecycle event created we add the following code. This will listen for the modal-closed event from the SimpleModal vue component.

/**
 * vue component lifecycle method where we setup listener
 * for when the modal is closed
 */
created() {
  this.$on("modal-closed", this.modalCloseHandler);
}
Enter fullscreen mode Exit fullscreen mode

Next we need to make a change to how we call the component to appropriately handle the event.

First we add the property parent to the component so we can send the event back to this component, the parent; we assign it the vale this

Also notice there is no more listening for onDismiss and process the response; all of that is now handled with the event listener modal-closed

/**
 * when the user clicks button, we open the modal
 */
async openModal() {
  let modal = await this.$ionic.modalController.create({
    component: SimpleModal,
    componentProps: {
      parent: this,
      propsData: {
        timeStamp: new Date()
      }
    }
  });

  // show the modal
  await modal.present();
}
Enter fullscreen mode Exit fullscreen mode

We now handle the dismiss with the call inside of the modalCloseHandler

modalCloseHandler(_value) {
   console.log("modal-closed", _value);

   if (_value.success) {
      // only on success
      alert(JSON.stringify(_value.noteInfo, null, 2));
   }
},
Enter fullscreen mode Exit fullscreen mode

Changes To SimpleModal Component

The only change needed here is to modify the modalClose method to emit the event instead of calling this.$ionic.modalController.dismiss

modalClose: function(success) {
   let response = {
      success,
      noteInfo: success ? this.noteInfo : null
   };
   this.$parent.$emit("modal-closed", response);
}
Enter fullscreen mode Exit fullscreen mode

Either approach can work, but I wanted to investigate an approach to process events from the Modal without having to actually close the modal and this approach can solve that problem.

Benefits of Emitting Events

We dont always want to just close the modal...Useless example, tracking when a form field changes?

<ion-item>
  <ion-input-vue
    type="text"
    name="title"
    placeholder="Title for note..."
    v-model="noteInfo.title"
    @ionChange="titleChanged"
  ></ion-input-vue>
</ion-item>
Enter fullscreen mode Exit fullscreen mode

add the code for the function titleChanged to the methods section of the SimpleModal component

titleChanged: function(_value) {
  this.$parent.$emit("modal-title-changed", _value.detail);
},
Enter fullscreen mode Exit fullscreen mode

Then in the parent component App add an additional listener to the onCreated lifecycle event handler.

  created() {
    this.$on("modal-closed", this.modalCloseHandler);
    this.$on("modal-title-changed", function(d) {
      console.log(d);
    });
  }
Enter fullscreen mode Exit fullscreen mode

Project Source Code

Here is the gist with the source code from the project Part One

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