Render a Vue app using a promise, and await user input
Here's a simple example which does the following:
- The Vue component is instantiated from a template and appended to the
<body>
element, rather than from an existing DOM element (in case you don't want the UI to be initially visible). - The promise is only resolved with the inputted text when the submit button is clicked. The component instance is destroyed and removed from the DOM.
const InputUI = {
template: '#input-ui',
data() {
return {
value: '',
};
},
};
function getInput() {
return new Promise(resolve => {
const inputUI = new Vue(InputUI);
inputUI.$once('submit', value => {
inputUI.$destroy();
inputUI.$el.remove();
resolve(value);
});
inputUI.$mount();
document.body.appendChild(inputUI.$el);
});
}
getInput().then(value => alert(value));
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>
<template id="input-ui">
<div>
<input v-model="value">
<button @click="$emit('submit', value)">Submit</button>
</div>
</template>
If you're using single file components, you would structure your code similar to this:
InputUI.vue
<template>
<div>
<input v-model="value">
<button @click="$emit('submit', value)">Submit</button>
</div>
</template>
<script>
export default {
data() {
return {
value: '',
};
},
};
</script>
main.js
import Vue from 'vue';
import InputUI from './InputUI.vue';
function getInput() {
return new Promise(resolve => {
const InputUIVue = Vue.extend(InputUI);
const inputUI = new InputUIVue();
inputUI.$once('submit', value => {
inputUI.$destroy();
inputUI.$el.remove();
resolve(value);
});
inputUI.$mount();
document.body.appendChild(inputUI.$el);
});
}
getInput().then(value => alert(value));
dendog
Updated on June 30, 2022Comments
-
dendog almost 2 years
I have a design question, I currently have a logic heavy JS script, which I have written as various promises and created a structure as the below:
init() .then(result => doSomethingA(result)) .then(result => doSomethingB(result)) .then(result => loadVueApp(result))
Now the
loadVueApp()
function calls does the following:new Vue({ el : '#app', render : h => h(App) });
Which renders my Vue app, and then the user can interact with the app, go to various screens, make selections which I store in a global
EventBus
type component.Now my question is, how should I pass the users choices back to my tower of promises? Should I be doing that at all?
I could resolve the
loadVueApp
right away based on simply the app appearing and then later make a function call back to the logic heavy script - but this does not feel as clean.Any ideas?
Thanks in advance.
-
dendog about 6 yearsThanks for this solution, it looks good - but this requires manual compilation or using the render function. I am using single file components.
-
Decade Moon about 6 yearsI'm not using render functions, there's nothing about my example that can't be translated to single file components.
-
dendog about 6 yearsFrom Docs:
However, if you are relying on mounting to an element with existing content as template (using the el option), you will still be subject to those limitations.
I would like to avoid adding the compiler if possible or am I missing something? -
Decade Moon about 6 yearsThe only reason why my answer is written in that way is to make it runnable online. To make it a single file component, all you have to do is put the
<template>
and component definition code into a .vue file as normal (and removetemplate: '#input-ui'
). Everything else stays the same. -
dendog about 6 yearsHmm sorry @Decade Moon , not sure what I am doing wrong :
- Component template requires a root element, rather than just text.
But also if I remove the reference to thetemplate
, how will the call tonew Vue()
know where to get the HTML from? -
Decade Moon about 6 yearsYou might need to instantiate
Vue.extend(InputUI)
because of the wayvue-loader
builds the component.