Skip to content

Instantly share code, notes, and snippets.

@danitrap
Last active September 25, 2021 13:44
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danitrap/e11c439f50d95b7206a2fb0e3c3f1a32 to your computer and use it in GitHub Desktop.
Save danitrap/e11c439f50d95b7206a2fb0e3c3f1a32 to your computer and use it in GitHub Desktop.
import { readonly, ref } from "vue";
/**
* Vue 3 custom hook to promisify a user's choice inside of a modal
*
* since the ask function returns a promise, it lets you
* await the user's choice and continue execution.
*
* @author Daniele Trapani
*/
export function usePromisedModal<T>() {
/**
* locally scoped variable to hold the promise's resolve function
* it's generically typed to allow code reuse
* it doesn't need to be reactive
*/
let resolveFn: (value?: T) => void = () => {};
/**
* reactive variable that holds the visibility of the modal
*/
const visible = ref(false);
/**
* make modal visible and store the resolve fn for later use
*/
const ask = (): Promise<T> => {
visible.value = true;
return new Promise((resolve) => {
resolveFn = resolve;
});
};
/**
* hide modal and call resolve function with user's choice
* @param value user's choice
*/
const tell = (value: T): void => {
visible.value = false;
resolveFn(value);
};
return {
visible: readonly(visible),
ask,
tell,
};
}
@danitrap
Copy link
Author

danitrap commented Jul 8, 2020

Usage:

<template>
    <div>
        <button @click="show">Show modal</button>
        <div v-if="visible">
            Do you agree?
            <button @click="tell('agree')">I Agree</button>
            <button @click="tell('decline')">I Decline</button>
        </div>
        <span>Result: {{ result }}</span>
    </div>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import { usePromisedModal } from "../composables/usePromisedModal";

export default defineComponent({
    name: "test",
    setup() {
        const { visible, ask, tell } = usePromisedModal<string>();
        let result = ref("");

        const show = async () => {
            result.value = await ask();
            // do something else… this code runs after the user's has made their choice.
        };

        return {
            show,
            visible,
            tell,
            result
        };
    }
});
</script>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment