Max Vallee
Max Vallee

Reputation: 468

Event handler "Click away" OR "Tab out" of input box

I am writing some JS validation for a form. Validation functions are executed when user clicks away from the input field. Although Blur or Focusout work flawlessly when user clicks away, they only trigger "sometimes" when user tabs out.

So I'm forced to write an additional event listener for a keydown when keycode == 9 (ie, tab). Is there away to use OR || to merge two event listener so as not to repeat myself?

Something like:

elements.inputfield.addEventListener('click' || 'keydown', e => {
    (e.keyCode == "9") || e.target.addEventListener("blur", e => {
        validation();
    })
})

I know that the syntax above makes no sense, but I'm just trying to convey my logic: two event listeners ('click' watching for 'blur' AND/OR 'keydown' watching for keyCode==9), and one output.

Is this possible?

For those curious, my current code looks like this and works well on click away (blur), but not reliable on tab out:

elements.userform.addEventListener('click', e => {
    if (e.target.matches('.input-box')) {
        e.target.addEventListener("blur", e => {
            userFormView.isEmpty(e.target)
        })
    }
})

Upvotes: 0

Views: 4077

Answers (2)

Wel not exactly like your doing, but you can simply make one function that has the same result, for example:

function do(e) {
    (e.keyCode == "9") || e.target.addEventListener("blur" , e =>{
          validation()
         //other stuff
    }
}
elements.inputfield.addEventListener('click', do);
elements.inputfield.addEventListener('keydown', do);

is that what you're looking for?

You can write a function that shortens it, for example:

function eventify(el, events, func) {
    var eventList = events.split("||").map(x=>x.trim());
    eventList.forEach(x => {
        el.addEventListener(x, func);
    })
}

eventify(elements.inputfield, "click || keydown", e => {
  if (e.target.matches('.input-box')){
    e.target.addEventListener("blur", e =>{
      userFormView.isEmpty(e.target)
    })
  }
})

or make it part of the html prototype of any HTML element for shorthand:

Object.defineProperty(HTMLElement.prototype, "eventify", {
    get() {
        return function(events, func) {
            var eventList = events.split("||").map(x=>x.trim());
            eventList.forEach(x => {
               this.addEventListener(x, func);
            })
        }
    }
})

then

elements.inputfield.eventify("click || keydown", e => {
      if (e.target.matches('.input-box')){
        e.target.addEventListener("blur", e =>{
          userFormView.isEmpty(e.target)
        })
      }
})

Upvotes: 1

Darshana Pathum
Darshana Pathum

Reputation: 669

We can't do that. But you can use it using a named function and passing that into your event listener, you can avoid having to write the same code over and over again.

// Setup your function to run on various events
var myFunction= function (event) {
    // Do something...
};

// Add our event listeners
elements.inputfield.addEventListener('click', myFunction, false);
elements.inputfield.addEventListener('keydown', myFunction, false);

Upvotes: 1

Related Questions