Reputation: 1625
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
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
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
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
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