Open a Vuetify dialog from a component template in VueJS

vuetify open dialog programmatically
vuetify dialog open event
vuetify dialog close event
vuetify dialog return-value
v-dialog vuetify
vuetify confirm dialog
vue dialog
vuetify dialog overlay

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?

You can open the dialog using custom events and using an event bus for non parent-child communication.

If your application gets a bit more complex I recommend you use Vuex for state management.


Event bus solution:

In your main.js or in a new file create and export a new Vue instance :

export const bus = new Vue()

In app.vue import the busand emit the event:

<template>
  <div>
    <button @click.prevent="openMyDialog()">my button</button>
  </div>
</template>

<script>
  import {bus} from '../main' // import the bus from main.js or new file
  export default {
    methods: {
      openMyDialog () {
        bus.$emit('dialog', true) // emit the event to the bus
      }
    }
  }
</script>

In modal.vue also import the bus and listen for the event in the created hook:

<script>
  import {bus} from '../main'    
  export default {
    created () {
      var vm = this
      bus.$on('dialog', function (value) {
        vm.dialog = value
      })
    }
  }
</script>

Dialog component, The Tidelift Subscription is a managed open source subscription for application dependencies. ads by Vuetify. Form. Just a simple example of a  The v-dialog component inform users about a specific task and may contain critical information, require decisions, or involve multiple tasks. Use dialogs sparingly because they are interruptive. Use dialogs sparingly because they are interruptive.

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">    
   <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>

Vuetify Confirm Dialog component that can be used locally or , Vuetify Confirm Dialog component that can be used locally or globally getting error as "Property 'open' does not exist on type 'Vue | Element | Vue[] | Element[]'. <template> <v-dialog v-model="show" :max-width="options.width" :style="{  Vuetify Material Dashboard PRO is a beautiful theme built over Vuetify, Vuex and Vuejs. Vuetify Material Dashboard PRO is the official Vuejs version of the Original Material Dashboard PRO.

There are many ways to do it such is Vuex,Event Bus,Props with which you can manage whether the modal have to open or to close.I will show you my favourite way using the .sync modifier:

First i will simplify you question(the code part)

Parent component

<template>
   <div>
     <button @click="dialog=true">Open Dialog</button>
     <Child :dialog.sync="dialog" />
   </div>
</template>

<script>
import Child from './Child.vue'
export default {
    components: {
      Child
    },
    data: {
      return {
        dialog: false
      }
   }
}
</script>

Child(Dialog) Component

<template>
  <v-layout row justify-center>
    <v-dialog v-model="dialog" persistent 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 @click.native="close">Close</v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </v-layout>
</template>

<script>

  export default {
    props: {
        dialog: {
        default: false
      }
    },
    methods: {
        close() {
        this.$emit('update:dialog', false)
      }
    }
  }

</script>

Vuetify Tutorial #23 - Popups (dialogs), We'll eventually be using the dialog to create a form for adding new projects. VUE & FIREBASE Duration: 4:54 Posted: Dec 7, 2018 Vuetify Dialog Loader with SnackBar component. VuetifyDialogLoader. Vuetify Dialog Loader Component (with SnackBar) component that can be used locally or globally. This component use the Vuetify Dialog Loader to show loading dialog, with optional SnackBar notifications (snackbar disabled by default) Insert component where you want to use it:

Simple minimal working example

codepen

Pass value prop as value to v-dialog component, and from child dialog emit input event whenever you want to close it:

//CustomDialog.vue
<v-dialog :value="value" @input="$emit('input')">
  <v-btn color="red" @click.native="$emit('input')">Close</v-btn>
</v-dialog>
...
props:['value']

and add v-model to your parent

//Parent.vue
<custom-dialog v-model="dialog">

So no custom event bus, no data, no watch, no computed.

How to programmatically open a confirmation dialog using Vuetify , Create a single confirmation dialog which uses a Vuex store variable. in the original component, I can simply wait for the action to resolve and prceed More posts from the vuejs community. 122 WebSockets in Vue.js - Beginners tutorial. Because we want our modal dialog component to be as flexible as possible, we create a separate component to display the content inside the modal. The ModalLogin component will contain a simple user login form. The modal content should contain a cancel button which closes the modal dialog immediately.

The most simpler way I found to do it is:

in data() of component, return a attribute, let's say, dialog.

When you include a component, you can set a reference to your component tag. E.g.:

import Edit from '../payment/edit.vue';

<edit ref="edit_reference"></edit>

Then, inside my component, I have set a method:

        open: function () {
            var vm = this;

            vm.dialog = true;
        }

Finally, I can call it from parent, using:

  editar(item)
  {
      var vm = this;

      vm.$refs.edit_reference.open();
  }

Composing Reusable Modal Dialogs with Vue.js, Playing off of the example above, we might start with something like this: Template for the modal component --> <div class="modal-mask"  Composing Reusable Modal Dialogs with Vue.js Update Aug 12, 2017: All of the examples have now been updated for Vue 2.0! I was working on an app idea with Vue.js and Laravel the other day and needed to create some modal forms that were submitted asynchronously.

Building a Modal Dialog with Vue.js and Vuex, Learn how to build a modal dialog component in Vue.js powered by Vuex using the Before we start coding, let's think about some challenges and As you can see above, we've added a login button in the template and a  Vue.js - The Progressive JavaScript Framework. Modal Component Example. Features used: component, prop passing, content insertion, transitions.

How to implement a model component in a , Hi, I want to implement a modal component, a dialog, like this one in the start as this Vue.component('modal', { template: '#modal-template', I am… to try Vuetify framework - there are a lot of cool reusable components and  When the user logs in and this component is rendered I saw the dialog being rendered and closing. If I hit f5 it reloads the page and dialog is showed correctly. If I do the bellow modification it works, but I don't want to solve the problem this way since it won't work for all cases, it will depend on the speed of the user computer/internet.

How to implement a general dialog used throughout , I have implemented a suitable AccessControl component using Vuetify <template​> <v-dialog v-model="show" persistent max-width="500px">  Reusable Modal component supports own custom HTML and classes. Reusable Modal component, supports own custom HTML, text and classes. Vuetify Dialog Loader with SnackBar component. Vue2-Simplert as Vue.js Plugins. When we using vue2-simplert, we will need to import the library in every place we need.

Comments
  • I tried it and got this _'bus' is not defined _ error after running npm run dev: error in ./src/components/Modal.vue ✘ http://eslint.org/docs/rules/no-undef 'bus' is not defined src/components/Modal.vue:23:5 bus.$on('dialog', function (value) { ^ ✘ 1 problem (1 error, 0 warnings) Errors: 1 http://eslint.org/docs/rules/no-undef @ ./src/main.js 37:0-43 @ multi ./build/dev-client babel-polyfill ./src/main.js What did I miss?
  • Oh, sorry! I corrected my answer! Of course we have to export and import the bus in the "moduled" version. For not messing it up again I have also tested the code :) Sorry again for that quick shot.
  • Thanks for your help! :) There was an error because the data part was missing. Is this the correct/best-practice fix? import {bus} from '../main' export default { data () { return { dialog: false } }, created () { var vm = this bus.$on('dialog', function (value) { vm.dialog = value }) } } Thanks again
  • You're welcome :) Glad to help! You find the event bus solution in the official docs: vuejs.org/v2/guide/…. Here it's just adapted for the module system. So I would say it's a best practice. But it's only suited for small projects. I could imagine since you're using vuetify that your app could get a bit bigger. And for bigger apps it's recommended to use Vuex: vuex.vuejs.org/en . It's pretty easy and straight forward. That's what I usually use.
  • Same principle. You would emit an event in your card.vue and listen to it in the app.vue.
  • This is an ABSOLUTELY perfect answer I think. Thank you. This works perfect!
  • Tried that, it works as necessary. Better get this to the top!
  • If the above doesn't work, change your child's computed property to use $attrs like this: show: { get () { return this.$attrs.value }, set (value) { this.$emit('input', value) } }
  • This is the best solution IMO. No event bus needed!
  • Are you sure? vuejs.org/v2/guide/components-custom-events.html#sync-Modifier
  • I found a documentation page stating that, but just found medium.com/front-end-weekly/… which states that .sync has been re-added in 2.3 - but it didn't work for me.
  • Thank you. Why do you write "var vm = this" instead of the shorter "this.$refs.edit_reference.open()"?
  • Because of the scope problem, although I not really sure it would be a problem, just to be safe as I was learning the concept of components.
  • I need to open that modal also from within the navigation menu. How to do that?
  • When you create v-model you can bind v-model and when you make that v-model true your model will appear and when you make it false it will hide.