user3711357
user3711357

Reputation: 1625

Is it possible to execute $emit as synchronous mode and get the result back from emit event

Is it possible to execute as emit as synchronous and get the result back in calling method itself. So, I want to execute next statement after the $emit completed. its as below:

Parent component has method, 
                 doCustomValidation();

child component is as follow:
methods:
{
  Save: function(){
 // Can I get the response here from parent component and then, execute 
    doGenericValidation ?

 var errorFields = this.$emit('custom-validation');  
   doGenericValidation(errorFields);   //this is generic validations
}

Upvotes: 4

Views: 6991

Answers (4)

KushalSeth
KushalSeth

Reputation: 4669

I also have the same problem statement, where I have my validations method in parent and wants to check that in child component, before performing the save action.

If you want to perform something like this. then a better option is to pass the method as props. It may not make sense to await for the response of $emit.

Example:

The method that I need to call is doCustomValidation(). of parent-component from child-component's save() method.

Parent Codebase (shown only the required codebase where names matching to the asked question):

<template>
    <child-component
      :doCustomValidation="doCustomValidation"
    />
</template>
<script lang="ts">
import ChildComponent from "@/students/ChildComponent.vue";

export default defineComponent({
    components: { 
        "child-component": ChildComponent,
    },
    methods: { 
        doCustomValidation() { 
           let isValid = false;
           // do your stuff here, even you can access the 
           // validation params and show the validations here.
           return isValid;
        }
    }
})
</script>

Child Codebase (shown only the required codebase where names matching to the asked question):

<script lang="ts">
export default defineComponent({
  props: ["doCustomValidation"],
  methods: { 
      save() {
         // calling parent validation method and 
         // this will wait for result.
         if(this.doCustomValidation()) {
            // perform Save here.
         }
      }
  }
)}
</script>

Upvotes: 0

vir us
vir us

Reputation: 10715

You can make a promise based wrapper for emit and wait for its result.

Here is a pretty generic solution I've ended up creating for my projects:

    async emitPromised(method, ...params){
        let listener = this.$listeners[method] || this.$attrs[method] || this[method]
        if(listener){
            let res = await listener(...params)
            return res === undefined || res
        }
        return false
    },

Now you can use it like this:

        async onDelete(){
            this.isDeleting = true
            let res = await this.emitPromised("delete")
            this.isDeleting = false
            if(res){
                this.closeConfirm()
            }
        },

You can include this method through mixin or attach it globally to Vue instance so it's accessible to all components.

As a note, $listeners store all methods bound to this component with @ or v-on (like <MyComponet @click="onClick"/>) while $attrs store everything passed to the component using v-bind or : (like <MyComponet :click="onClick"/>)

Upvotes: 3

Flame
Flame

Reputation: 7580

You shouldnt attempt to make this synchronous. Instead, you might be able to use this idea:

methods: {
    myMethod() {
        // Pass a function as a parameter.
        this.$emit('custom-validation', this.onComplete);
    },
    onComplete() {
        // Do stuff after custom-validation has completed.
    }
}

And then in whichever component uses your event:

<some-component @custom-validation="doStuff" />
<script>
...
methods: {
    doStuff(done) {
        // Your logic here. After that, call the callback function.
        done();
    }
}
...

Upvotes: 11

Steven Spungin
Steven Spungin

Reputation: 29109

No. $emit will always be queued. There also may be multiple listeners, so a return value does not really make sense.

As a workaround, you can send a function in as a property, and then call it directly.

Upvotes: 2

Related Questions