Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open a Vuetify dialog from a component template in VueJS

I'm using the VueJS Vuetify framework and I need to open a dialog - that gets imported as a component template - from another template. Once the Menu button in App.vue got clicked, the Modal should open. Here is my setup:

  • App.vue = navigation template with Menu button
  • Modal.vue = Modal template, imported as global in main.js

main.js

import Modal from './components/Modal.vue' Vue.component('modal', Modal) 

Modal.vue Template:

<template>   <v-layout row justify-center>     <v-btn color="primary" dark @click.native.stop="dialog = true">Open Dialog</v-btn>     <v-dialog v-model="dialog" max-width="290">       <v-card>         <v-card-title class="headline">Use Google's location service?</v-card-title>         <v-card-text>Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.</v-card-text>         <v-card-actions>           <v-spacer></v-spacer>           <v-btn color="green darken-1" flat="flat" @click.native="dialog = false">Disagree</v-btn>           <v-btn color="green darken-1" flat="flat" @click.native="dialog = false">Agree</v-btn>         </v-card-actions>       </v-card>     </v-dialog>   </v-layout> </template> <script>   export default {     data () {       return {         dialog: false       }     }   } </script> 

How to open the dialog?

like image 221
Tom Avatar asked Dec 30 '17 15:12

Tom


1 Answers

No event bus needed and v-model

Update:

When I first answered this, I posted my answer as a "workaround", since it didn't felt completely "right" at the time and I was new to Vue.js. I wanted to open or close the dialog by using a v-model directive, but I couldn't get there. After a time I found how to do this in the docs, using the input event and the value property, and here's how I think it should be done without an event bus.

Parent component:

<template>    <v-btn color="accent" large @click.stop="showScheduleForm=true">        <ScheduleForm v-model="showScheduleForm" /> </template>  <script> import ScheduleForm from '~/components/ScheduleForm'  export default {   data () {     return {       showScheduleForm: false     }   },   components: {     ScheduleForm   } } </script> 

Child component (ScheduleForm):

<template> <v-dialog v-model="show" max-width="500px">   <v-card>     <v-card-actions>       <v-btn color="primary" flat @click.stop="show=false">Close</v-btn>     </v-card-actions>   </v-card> </v-dialog> </template>  <script> export default {   props: {      value: Boolean   },   computed: {     show: {       get () {         return this.value       },       set (value) {          this.$emit('input', value)       }     }   } } </script> 

Original answer:

I was able to work around this without the need for a global event bus.

I used a computed property with a getter AND a setter. Since Vue warns you about mutating the parent property directly, in the setter I simply emitted an event to the parent.

Here's the code:

Parent component:

<template>    <v-btn color="accent" large @click.stop="showScheduleForm=true"></v-btn>       <ScheduleForm :visible="showScheduleForm" @close="showScheduleForm=false" /> </template>  <script> import ScheduleForm from '~/components/ScheduleForm'  export default {   data () {     return {       showScheduleForm: false     }   },   components: {     ScheduleForm   } } </script> 

Child component (ScheduleForm):

<template> <v-dialog v-model="show" max-width="500px">   <v-card>     <v-card-actions>       <v-btn color="primary" flat @click.stop="show=false">Close</v-btn>     </v-card-actions>   </v-card> </v-dialog> </template>  <script> export default {   props: ['visible'],   computed: {     show: {       get () {         return this.visible       },       set (value) {         if (!value) {           this.$emit('close')         }       }     }   } } </script> 
like image 183
Matheus Dal'Pizzol Avatar answered Sep 17 '22 11:09

Matheus Dal'Pizzol