I have a component called styled-input
and it's an input with styles, icons, validation, etc.
I am trying to use addEventListener
inside a custom directive to listen to events and make things happen.
<styled-input
v-model=""
v-on:input=""
v-on:blur=""
></styled-input>
Internally:
value
is a prop (allowing for v-model
binding outside)
<template>
<div>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
v-on:blur="$emit('blur', $event.target.value)"
/>
</div>
</template>
I'm trying to addEventListener
s to the tag through custom directives for custom validation.
<styled-input
v-model=""
v-custom-validator:credit-card
></styled-input>
Inside the directive I am using addEventListener
to listen to events from the input field.
Vue.directive('custom-validator', {
bind: function(el, binding) {
el.addEventListener('blur', (event) => {
// Does not fire
});
el.addEventListener('input', (event) => {
/// Fires
});
},
});
Why doesn't the blur event fire, while the input event fires?
How can I get the blur event to fire?
The blur event fires when an element has lost focus. The event does not bubble, but the related focusout event that follows does bubble. The opposite of blur is the focus event, which fires when the element has received focus. The blur event is not cancelable.
onblur fires when a field loses focus, while onchange fires when that field's value changes. These events will not always occur in the same order, however. In Firefox, tabbing out of a changed field will fire onchange then onblur, and it will normally do the same in IE.
The blur event fires when focus is lost. By default, a div element cannot have the focus in the first place so it can't be lost. If you set tabindex on a div, then it can gain the focus, but you should almost always be using a more appropriate element (such as a button) when you think about making interactive controls.
You are not picking the blur
because you are not specifying the useCapture
argument. It is mandatory because blur
event does not bubble. So adding the useCapture
would fix your problem:
el.addEventListener('blur', (e) => {
// it will work now
}, true); // useCapture is the third argument to addEventListener
From the your code (and see demo below), it may seem that when blur
and input
are triggered, the .addEventListener()
picks what was emitted by $emit()
. That is not the case.
You may get that idea because, besides those $emit()
s at your v-on
s, the <input>
will also trigger the native events blur
and input
.
So what you actually have is two different kinds of events for blur
and two for input
(see demo below).
$emit()
?$emit()
is internal to Vue. It is a part or every Vue instance events interface.
.addEventListener()
is for native DOM events. It will listen to .dispatchEvent()
s, not $emit()
s.
To listen to Vue's $emit()
s you must use Vue's .$on()
.
See demo below. Notice the e
(event) object from the .$on()
and from the .addEventListener()
are different.
Vue.component('my-comp', {
template: '#styled-input-tpl',
props: ['value']
});
Vue.directive('my-directive', {
bind: function (el, binding, vnode) {
vnode.componentInstance.$on('blur', function (e) {
console.log('received $on(blur) - event value:', event);
});
vnode.componentInstance.$on('input', function (e) {
console.log('received $on(input) - event value:', e);
});
el.addEventListener('blur', (e) => {
console.log('received NATIVE(blur) - event value:', e.target);
}, true); // <======================================================= IMPORTANT
el.addEventListener('input', (e) => {
console.log('received NATIVE(input) - event value:', e.target);
});
}
})
new Vue({
el: '#app'
})
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<template id="styled-input-tpl">
<div>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
v-on:blur="$emit('blur', $event.target.value)"
/>
</div>
</template>
<div id="app">
Edit the input, focus out, and check the console.
<my-comp v-my-directive :value="'edit me'"></my-comp>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With