-
-
Save eolant/ba0f8a5c9135d1a146e1db575276177d to your computer and use it in GitHub Desktop.
<template> | |
<v-dialog v-model="dialog" :max-width="options.width" :style="{ zIndex: options.zIndex }" @keydown.esc="cancel"> | |
<v-card> | |
<v-toolbar dark :color="options.color" dense flat> | |
<v-toolbar-title class="white--text">{{ title }}</v-toolbar-title> | |
</v-toolbar> | |
<v-card-text v-show="!!message" class="pa-4">{{ message }}</v-card-text> | |
<v-card-actions class="pt-0"> | |
<v-spacer></v-spacer> | |
<v-btn color="primary darken-1" text @click.native="agree">Yes</v-btn> | |
<v-btn color="grey" text @click.native="cancel">Cancel</v-btn> | |
</v-card-actions> | |
</v-card> | |
</v-dialog> | |
</template> | |
<script> | |
/** | |
* Vuetify Confirm Dialog component | |
* | |
* Insert component where you want to use it: | |
* <confirm ref="confirm"></confirm> | |
* | |
* Call it: | |
* this.$refs.confirm.open('Delete', 'Are you sure?', { color: 'red' }).then((confirm) => {}) | |
* Or use await: | |
* if (await this.$refs.confirm.open('Delete', 'Are you sure?', { color: 'red' })) { | |
* // yes | |
* } | |
* else { | |
* // cancel | |
* } | |
* | |
* Alternatively you can place it in main App component and access it globally via this.$root.$confirm | |
* <template> | |
* <v-app> | |
* ... | |
* <confirm ref="confirm"></confirm> | |
* </v-app> | |
* </template> | |
* | |
* mounted() { | |
* this.$root.$confirm = this.$refs.confirm.open | |
* } | |
*/ | |
export default { | |
data: () => ({ | |
dialog: false, | |
resolve: null, | |
reject: null, | |
message: null, | |
title: null, | |
options: { | |
color: 'primary', | |
width: 290, | |
zIndex: 200 | |
} | |
}), | |
methods: { | |
open(title, message, options) { | |
this.dialog = true | |
this.title = title | |
this.message = message | |
this.options = Object.assign(this.options, options) | |
return new Promise((resolve, reject) => { | |
this.resolve = resolve | |
this.reject = reject | |
}) | |
}, | |
agree() { | |
this.resolve(true) | |
this.dialog = false | |
}, | |
cancel() { | |
this.resolve(false) | |
this.dialog = false | |
} | |
} | |
} | |
</script> |
Standing on the shoulders of the giants before me, I was able to get a global confirm
ation function working with Nuxt.js:
-
In the layout component where the dialog is place:
<app-confirmation-dialog ref="confirm" /> ... //because I'm using Class based components I used an `@Ref()` shorthand, but using $refs in the RH side of the assignment below should work too: @Ref() readonly confirm!: AppConfirmationDialog ... // the real magic?? mounted(): void { this.$nuxt.$root.$confirm = this.confirm.open }
-
Its usage in other components:
await this.$root.$confirm( 'Skip Day', 'Are you sure you want to toggle the Skip Day status?', { color: 'red', })
-
Most likely because I am using Typescript I had to add a Nuxt plugin with:
import { Options } from '@/types' declare module 'vue/types/vue' { interface Vue { $confirm(title: string, message: string, options: Options): Promise<boolean> } }
-
and I had a type defined in a file shared between the plugin and the other components:
export interface Options { color?: string width?: number zIndex?: number }
Why use @click.native
when @click
seems to do the trick? Is there any scenario when a simple @click
is not enough?
If you need to implement it on vue3+vuetify3, you can refer to this article https://juejin.cn/post/7102240700774744095
<v-dialog
v-model="dialog"
@update:model-value="atDialogUpdate"
>
Add this function inside confirm dialog component so it will resolve with false if dialog is closed by clicking outside
function atDialogUpdate(val) {
if (!val) {
resolve(false);
}
}
If using in multiple places then confirmDialog component can be placed in root #app component like this
<div id='#app'>
<confirmDialog :ref='store.setConfirmDialogRef' />
</div>
then in pinia store or any shared state
state: () => ({
confirmDialogRef: null,
}),
actions: {
setConfirmDialogRef(val) {
this.confirmDialogRef = val;
},
}
The store.setConfirmDialogRef method will update ref in store.
then in any function
async function submit() {
if (!await store.confirmDialogRef.open(
"You sure?",
"Positive?",
)) {
return;
}
// axios.post
}
If you are using the
Composition API
plugin, you can useprovide/inject
plus auseDialog
composable that injects the show dialog function. Cleanest and TypeScript friendly!Here's how you would call it:
Full implementation here: https://gist.github.com/wobsoriano/1e63708d7771c34f835c0f6e3c5e731a