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>
first we import the modal component
import SimpleModal from "./components/SimpleModal.vue";
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));
}
}
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})
}
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})
}
}
};
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>
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: {}
}
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: ""
}
};
}
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);
}
},
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: ""
}
};
}
};
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);
}
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();
}
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));
}
},
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);
}
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>
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);
},
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);
});
}
Project Source Code
Here is the gist with the source code from the project Part One
Top comments (16)
It is possible to bind props with a new modal instance?
not sure I understand the question?
Also, I don't create modals this way anymore, I use the template approach, I find it to be much cleaner
Take a look here: github.com/aaronksaunders/ionic-vu...
I think David means data: { name: "Why Data" } in Detail.vue does not bind to the props in SimpleModal.vue. The default values are used in the Modal.
I have the same problem and get the warning:
[Vue warn]: Extraneous non-props attributes (data) were passed to component but could not be automatically inherited because component renders fragment or text root nodes.
I tried to figure it out myself, but am a little bit stuck by now.
have you looked at the updated code sample referenced above? This post is over a year old and ionic has changed how they manage modals. If you have a code sample project somewhere I am happy to take a look
Yes, I have cloned the project with updated code from github.com/aaronksaunders/ionic-vu....
I have changed
data: {
name: "Why Data"
}
into
data: {
title: "Why Data"
}
but both do not show "Why Data" in the title of the modal, but "Super Modal" instead.
I run Ionic Framework : @ionic/vue 5.5.2 with vue@3.0.4
to change the title of the modal, you need to set the modals title property, you are changing the data property which has no impact on the modal
I think you mean:
props: {
title: { type: String, default: "Super Modal" }
},
But how do I change this using parameters from detail.vue?
Thank you, it's working now.
Thanks, please like and subscribe to my YouTube channel, trying to get my subscribers over 2000!! And you will get updated when I push new content
How can it be adapted to be able to call the modal from any other component?
Thanks
i dont this that is how component based frameworks are meant to work. You should put the contents of the modal in a separate component that can be utilized on different locations in your app
Thanks. I meant the modal component to avoid the import in every component it's called. The content of the modal differs if arrive from one button or link.
Vuejs Event bus can be used in ionic?
yes Ionic just provides web components, all the regular vue stuff is still there
Thanks for the example. Have you succeeded to add swipeToClose to modals?
I'm having issues getting this to work, but I don't know if it's even supported in the Ionic Vue beta?
For reference this is my method for opening the modal (which works perfectly fine - except for the swipeToClose):
openTaskDrawer(task) { return this.modal = this.$ionic.modalController .create({ component: TaskDrawer, presentingElement: this.$el, swipeToClose: true, componentProps: { propsData: { task: task } }, }) .then(m => m.present()) }
tryed to make a video, but jacked up the sound... here it is for now until i get a chance to redo the video track youtu.be/nEkJWKSXcDM