dendog
dendog

Reputation: 3328

Render a Vue app using a promise, and await user input

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.

Upvotes: 3

Views: 12914

Answers (1)

Decade Moon
Decade Moon

Reputation: 34286

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));

Upvotes: 5

Related Questions