Is it possible to emit a custom event from the directive in the component to which this directive is attached.
I was expecting it to work as described in example, but it does not.
Example:
//Basic Directive
<script>
Vue.directive('foo', {
bind(el, binding, vnode) {
setTimeout(() => {
//vnode.context.$emit('bar'); <- this will trigger in parent
vnode.$emit('bar');
}, 3000);
}
});
</script>
//Basic Component
<template>
<button v-foo @bar="change">{{label}}</button>
</template>
<script>
export default{
data() {
return {
label: 'i dont work'
}
},
methods: {
change() {
this.label = 'I DO WORK!';
}
}
}
</script>
Any ideas on the matter? Am I missing something?
JSFiddle: https://jsfiddle.net/0aum3osq/4/
Update 1:
Okay, i've found that if I call vnode.data.on.bar.fn();
(or fns()
in latest Vue versions) in directive it will trigger bar
event handler.
Update 2:
Temporary solution:
/*temp. solution*/
var emit = (vnode, name, data) => {
var handlers = vnode.data.on;
if (handlers && handlers.hasOwnProperty(name)) {
var handler = handlers[name];
var fn = handler.fns || handler.fn;
if (typeof fn === 'function') {
fn(data);
}
}
}
//Basic Directive
<script>
Vue.directive('foo', {
bind(el, binding, vnode) {
setTimeout(() => {
emit(vnode, 'bar');
}, 3000);
}
});
</script>
You can emit custom native javascript events. Create a directive that dispatches an event from the node, using node.dispatchEvent
Which can be used like this
Your solution was not working for me. Indeed vnode.data.on was always undefined
What worked to trigger an event was
Hope this helps.
The above answers are great but some of them are out-of-date. Here's the way I solve the problem by integrating them into a workable POC.
Import the directives in main.js:
Use the directive with listening to the event emission in a Vue component:
Basically, in
vnode.context.$emit
, thebinding.expression
is the string (i.e., "hideElement" in this example) you declared in thev-close-outside
. To retrieve the emission from the directive, usethis.$on('hideElement')
to listen to it.So the solution I am using in Vue 2+ (considering there were no answers so far):
In directive add method:
And call it this way:
The benefits of an approach:
1 Keep the same code-style in your project, meaning that every handler can be declared as
v-on:handler_name
and be handled in meaningful (for developer) way. Other solutions, like sending callback as parameter, are sometimes confusing and not obvious without digging into documentation/code.2 Using built-in events system also allows to gracefully handle event objects. For example, this code will work perfectly fine:
EDIT:
In v2.1+ you can use this inside directive binding:
@euvl's solution is fine, but i think it's easier and cleaner to just pass a function as an argument to your directive. Seems to simplify the interface to your directive as well.
I know it is an old issue, but if someone has problems with this and it is not working. You can use use javascript custom events events.
now i can use it like
i do not have to set
$event
because the default is standard emitted as last param. this event has adetail
property, which contains your custom data in this case this object:src https://github.com/vuejs/vue/issues/7147