Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding eventListener to blur event on custom component?

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 addEventListeners 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?

like image 593
David Alsh Avatar asked Mar 16 '18 01:03

David Alsh


People also ask

What triggers blur event?

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.

What is difference between Blur and change event?

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.

Does Div have blur event?

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.


1 Answers

Why blur fails

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


Don't confuse Native DOM events with Vue events

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-ons, 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).


What is up with $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>
like image 60
acdcjunior Avatar answered Oct 08 '22 06:10

acdcjunior