[Vuejs]-Resolve promise inside method when button is clicked

0๐Ÿ‘

โœ…

I would suggest to use refs and save Promise resolve function until user clicks button

methods: {
  onClick() {
    this.resolve();
  },
  handleClick() {
    const popupRef = this.$refs.popupRef;
    const classList = popupRef.classList;
    return new Promise(resolve => {
        classList.toggle("show");
        this.resolve = resolve;
    })
    .then(() => {
       classList .toggle("show");
    })
  })
},

Example

Vue.config.devtools = false;
Vue.config.productionTip = false;

Vue.component("child-component", {
  props: {
    text: String,
    response: String,
    clicked: Boolean
  },
  template: `<div class="instruction">
    <div>{{text}}</div>
    <span ref="popupRef" class="popup">Click it!</span>
    <button v-if="!clicked" @click="onClick">Ok Done!</button>
    <div v-if="clicked">{{response}}</div>
  </div>`,
  methods: {
    onClick() {
      this.resolve();
    },
    handleClick() {
      const popupRef = this.$refs.popupRef;
      const classList = popupRef.classList;
      
      return new Promise(resolve => {
          classList.toggle("show");
          this.resolve = resolve;
        })
        .then(() => {
          classList.toggle("show");
        })
    },
  }
})

new Vue({
  el: '#container',
  data() {
    return {
      text: 'Show Instructions',
      disabled: false,
      instructions: [{
          id: 1,
          text: 'Eat something!',
          response: 'Nice!',
          clicked: false
        },
        {
          id: 2,
          text: 'Work',
          response: 'Wow!',
          clicked: false
        }
      ]
    }
  },
  methods: {
    async showInstructions() {
      this.disabled = true;
      this.text = "Showing instructions...";
      
      const combined = this.instructions.map((obj, index) => [
        obj,
        this.$refs.instructions[index]
      ]);
      
      for (let [instruction, ref] of combined) {
        await ref.handleClick();
        this.$set(instruction, 'clicked', true);
      }
      
      this.text = 'Processing...';
      
      setTimeout(() => {
        this.disabled = false;
        this.text = 'Show Instructions';
      
        this.instructions = this.instructions.map(instruction => ({
          ...instruction,
          clicked: false
        }))
      }, 500);
    }
  }
});
.instruction {
  border: 1px solid black;
  padding: 10px;
}

.popup {
  position: absolute;
  opacity: 0;
  padding: 10px;
  background: black;
  color: white;
  margin-top: -10px;
  margin-left: 90px;
  
}

.popup.show {
  opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="container">
  <child-component ref="instructions" :key="item.id" v-bind="item" v-for="item in instructions"></child-component>
  <button :disabled="disabled" @click="showInstructions">{{text}}</button>
</div>

Leave a comment