vue3-promise-dialog
Dialogs meet promises in Vue 3 !
This project does not provide any dialogs. Rather, it makes it easy to create your own dialogs and work with them using
promises. The dialogs can be opened by calling a function that returns a promise and once the user enters data into the
dialog and closes it, the promise resolves with the data the user entered.
Installation
Demos
Showcases the small dialog collection included in this repository as examples :
https://rlemaigre.github.io/vue3-promise-dialog/
A Vite + Vue 3 + Typescript project on Stackblitz featuring a confirm dialog which is probably the simplest use case of the library :
https://stackblitz.com/edit/vitejs-vite-nzzfdg?&terminal=dev
Introduction
Dialogs the usual way
If you need to use a dialog in a parent component, you usually do it by altering its script and template, something
along those lines :
<template>
<transition name=”…“>
<ConfirmDialog v-if=”show” @ok=”onOk()” @cancel=”onCancel()“></ConfirmDialog>
</transition>
</template>
<script>
// Set up a show ref, onOk and onCancel functions. Switch show to true to open the dialog.
</script>
That approach has several disadvantages :
It is verbose.
A dialog can only be opened from a parent Vue component, not from a JS/TS file.
There is no symmetry between requesting data from the user and from the server, yet it is the same kind of
asynchronous process that yields a value.
Everywhere you need to use the dialog, you need to set up some logic in the parent component :
The dialog tag in the template
A ref that controls the dialog visibility
Callbacks that handle clicks on dialog buttons
Things get nasty when a parent component needs to use several dialogs.
Dialogs using promises
As we all know, requesting data from the server is an asynchronous process that is best handled with promises. For
example the Fetch API is a promise based API.
Now, just like fetching data from the server, requesting data from the user using a dialog is also an asynchronous
process that may complete with a value at some point in the future when the user closes the dialog. Why would the API to
fetch data from the user be any different than the API to fetch data from the server ?
Using promises, opening a confirm dialog (for example) is as simple as this :
let ok = await confirm(‘Are you sure you want to do this ?’);
if (ok) {
// Do something
}
The promise resolves to the value the user entered into the dialog when it is closed.
That approach has several advantages :
It is concise.
A dialog can be opened from a parent Vue component, or from any JS/TS file. It’s just a function call.
There is a pleasing symmetry between requesting data from the user and from the server.
No need to alter the code of a parent component to accommodate for the presence of the dialog.
A parent component can use many dialogs without becoming a mess.
Content of this repository
You may be familiar with the following Vue 2 project : vue-modal-dialog.
Unfortunately it hasn’t been ported to Vue 3. This repository demonstrates how the basic functionality of that project
can be easily recovered in Vue 3.
Directory structure
The core functionality is in the lib folder.
An example of a small dialog collection built upon the core functionality is in the src/dialogs folder. It is not
published on NPM since it is dependent on PrimeVue (for buttons and text fields) which you may not be using and the look
and feel you may be aiming for for your own dialogs may differ. Use it as inspiration to build your own dialog
collection.
Using the library
Plugin
Install the plugin like this :
The plugin defines the $close global function and makes it available in all components.
DialogWrapper
Your dialogs will open inside a DialogWrapper component. Include the DialogWrapper component at the root of your vue
app, after all other content. Internally DialogWrapper uses a transition tag to transition your dialogs in and out of
view. Use the transitionAttrs prop to control the transition : the value of that prop will be v-binded as is to the
transition tag inside the wrapper. So for example to set the name of the transition to dialog,
use :transition-attrs=”{name: ‘dialog’}”.
<div class="highlight highlight-text-html-basic position-relative overflow-auto" data-snippet-clipboard-copy-content="
<template>
<div id="app">
<DialogWrapper :transition-attrs="{name: ‘dialog’}"/>
</div>
</template>”>
<template>
<div id=”app“>
<!– your content –>
<DialogWrapper :transition-attrs=”{name: ‘dialog’}“/>
</div>
</template>