2

I have an issue that needs to be resolved.

a.ts


const open = ref<boolean>(false)
h(RowAction, {
  open: open,
  onDelete: () => {
    Data.remove().then(() => {}).catch(() => {}).finally(() => (open.value = false))
  }
})

RowAction.vue

<script lang="ts" setup>
defineProps<{open: boolean}>()
defineEmits<{ (e: 'delete'): void }>()
</script>

<template>
  <div>
    <button @click="$emit('delete')">
      delete
    </button>
  </div>
  <my-alert :open="open">
    <alert-tetx>test</alert-text>
    <button @click="open = false">close</button>
    <button @click="$emit('delete')">delete</button>
  </my-alert>
</template>

I want the delete event to run when clicked, and the alert to close after the promise resolves or rejects. However, I don't know why my code is not running.

2 Answers 2

0

Exposing and managing internal property open of RowAction could be not a perfect design pattern. Just provide a resolve/reject pair in the delete event to narrow scope of the problem to the event callback only:

Playground

RowAction.vue:

<script setup lang="ts" >

import {ref} from 'vue';
const open = ref(false);
const error = ref('');
const disabled = ref(false);
const $emit = defineEmits<{ (e: 'delete', defer: () => ReturnType<PromiseConstructor['withResolvers']>) }>()

function onDelete(){
    let needsResolving = false;
    error.value = '';
    $emit('delete', () => {
      needsResolving = true;
      disabled.value = true;
      const {promise, resolve, reject} = Promise.withResolvers();
      promise
        .then(() => open.value = false, e => error.value = e.message)
        .finally(() => disabled.value = false);
      return {promise, resolve, reject};
    });
    needsResolving || close();
}

function close(){
  open.value = false;
  error.value = '';
}

</script>

<template>
  <div>
    <button @click="open = true">
      delete
    </button>
    <dialog :open>
        <div> are you sure to delete ? </div>
        <div v-if="error" style="font-size: small;color: red;">{{ error }}</div>
        <button :disabled @click="close">close</button>
        <button :disabled @click="onDelete">delete</button>
    </dialog>
  </div>
</template>

App.vue

<script setup lang="ts">
import {h} from 'vue';
import RowAction from './RowAction.vue';

class Data{
  static remove(){
    return new Promise((resolve, reject) => {
          Math.random() > .5 ? 
            setTimeout(resolve, 1000) :
            setTimeout(() => reject(new Error('Operation has failed')), 1000);
        });
  }
}

function render(){
  return h(RowAction, {
    onDelete: async (defer) => {
      const {resolve, reject} = defer();
      Data.remove().then(resolve, reject);
    }
  });
}

</script>

<template>
  <label>With promise work</label>
  <render/>
  <label>Immediate</label>
  <row-action/>
</template>
Sign up to request clarification or add additional context in comments.

Comments

0

Given that events are props named onXXX you can define the delete event as a prop:

Playground

RowAction.vue

<script setup lang="ts" >

import {ref} from 'vue';

const props = defineProps<{
  onDelete: () => void | Promise<any>
}>();

const open = ref(false);
const error = ref('');
const disabled = ref(false);

async function onDelete(){
    error.value = '';
    disabled.value = true;
    try{
      await props.onDelete();
      close();
    }catch(e){
      error.value = e.message;
    }finally{
      disabled.value = false;
    }
}

function close(){
  open.value = false;
  error.value = '';
}

</script>

<template>
  <div>
    <button @click="open = true">
      delete
    </button>
    <dialog :open>
        <div> are you sure to delete ? </div>
        <div v-if="error" style="font-size: small;color: red;">{{ error }}</div>
        <button :disabled @click="close">close</button>
        <button :disabled @click="onDelete">delete</button>
    </dialog>
  </div>
</template>

App.vue

<script setup lang="ts">
import {h} from 'vue';
import RowAction from './RowAction.vue';

class Data{
  static remove(){
    return new Promise((resolve, reject) => {
          Math.random() > .5 ? 
            setTimeout(resolve, 1000) :
            setTimeout(() => reject(new Error('Operation has failed')), 1000);
        });
  }
}
const alert = msg=>window.alert(msg);
</script>

<template>
  <label>With promise work</label>
  <row-action @delete="Data.remove()"/>
  <label>Immediate</label>
  <row-action @delete="alert('deleted')"/>
</template>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.