adding multiple event listeners to one element

Viewed 206011

So my dilemma is that I don't want to write the same code twice. Once for the click event and another for the touchstart event.

Here is the original code:

document.getElementById('first').addEventListener('touchstart', function(event) {
    do_something();
    });

document.getElementById('first').addEventListener('click', function(event) {
    do_something(); 
    });

How can I compact this? There HAS to be a simpler way!

16 Answers

Simplest solution for me was passing the code into a separate function and then calling that function in an event listener, works like a charm.

function somefunction() { ..code goes here ..}

variable.addEventListener('keyup', function() {
   somefunction(); // calling function on keyup event
})

variable.addEventListener('keydown', function() {
   somefunction(); //calling function on keydown event
})

I have a small solution that attaches to the prototype

  EventTarget.prototype.addEventListeners = function(type, listener, options,extra) {
  let arr = type;
  if(typeof type == 'string'){
    let sp = type.split(/[\s,;]+/);
    arr = sp;   
  }
  for(let a of arr){
    this.addEventListener(a,listener,options,extra);
  }
};

Allows you to give it a string or Array. The string can be separated with a space(' '), a comma(',') OR a Semicolon(';')

I just made this function (intentionally minified):

((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, events, handler)

Usage:

((i,e,f)=>e.forEach(o=>i.addEventListener(o,f)))(element, ['click', 'touchstart'], (event) => {
    // function body
});

The difference compared to other approaches is that the handling function is defined only once and then passed to every addEventListener.

EDIT:

Adding a non-minified version to make it more comprehensible. The minified version was meant just to be copy-pasted and used.

((element, event_names, handler) => {

    event_names.forEach( (event_name) => {
        element.addEventListener(event_name, handler)
    })

})(element, ['click', 'touchstart'], (event) => {

    // function body

});

document.getElementById('first').addEventListener('touchstart',myFunction);

document.getElementById('first').addEventListener('click',myFunction);
    
function myFunction(e){
  e.preventDefault();e.stopPropagation()
  do_something();
}    

You should be using e.stopPropagation() because if not, your function will fired twice on mobile

This is my solution in which I deal with multiple events in my workflow.

let h2 = document.querySelector("h2");

function addMultipleEvents(eventsArray, targetElem, handler) {
        eventsArray.map(function(event) {
            targetElem.addEventListener(event, handler, false);
        }
    );
}
let counter = 0;
function countP() {
    counter++;
    h2.innerHTML = counter;
}

// magic starts over here...
addMultipleEvents(['click', 'mouseleave', 'mouseenter'], h2, countP);
<h1>MULTI EVENTS DEMO - If you click, move away or enter the mouse on the number, it counts...</h1>

<h2 style="text-align:center; font: bold 3em comic; cursor: pointer">0</h2>

What about something like this:

['focusout','keydown'].forEach( function(evt) {
        self.slave.addEventListener(evt, function(event) {
            // Here `this` is for the slave, i.e. `self.slave`
            if ((event.type === 'keydown' && event.which === 27) || event.type === 'focusout') {
                this.style.display = 'none';
                this.parentNode.querySelector('.master').style.display = '';
                this.parentNode.querySelector('.master').value = this.value;
                console.log('out');
            }
        }, false);
});

// The above is replacement of:
 /*   self.slave.addEventListener("focusout", function(event) { })
      self.slave.addEventListener("keydown", function(event) {
         if (event.which === 27) {  // Esc
            }
      })
*/

You can simply do it iterating an Object. This can work with a single or multiple elements. This is an example:

const ELEMENTS = {'click': element1, ...};
for (const [key, value] of Object.entries(ELEMENTS)) {
    value.addEventListener(key, () => {
        do_something();
    });
}

When key is the type of event and value is the element when you are adding the event, so you can edit ELEMENTS adding your elements and the type of event.

I'm new at JavaScript coding, so forgive me if I'm wrong. I think you can create an object and the event handlers like this:

const myEvents = {
  click: clickOnce,
  dblclick: clickTwice,
};

function clickOnce() {
  console.log("Once");
}

function clickTwice() {
  console.log("Twice");
}

Object.keys(myEvents).forEach((key) => {
  const myButton = document.querySelector(".myButton")
  myButton.addEventListener(key, myEvents[key]);
});
<h1 class="myButton">Button</h1>

And then click on the element.

Semi-related, but this is for initializing one unique event listener specific per element.

You can use the slider to show the values in realtime, or check the console. On the <input> element I have a attr tag called data-whatever, so you can customize that data if you want to.

sliders = document.querySelectorAll("input");
sliders.forEach(item=> {
  item.addEventListener('input', (e) => {
    console.log(`${item.getAttribute("data-whatever")} is this value: ${e.target.value}`);
    item.nextElementSibling.textContent = e.target.value;
  });
})
.wrapper {
  display: flex;
}
span {
  padding-right: 30px;
  margin-left: 5px;
}
* {
  font-size: 12px
}
<div class="wrapper">
  <input type="range" min="1" data-whatever="size" max="800" value="50" id="sliderSize">
  <em>50</em>
  <span>Size</span>
  <br>
  <input type="range" min="1" data-whatever="OriginY" max="800" value="50" id="sliderOriginY">
  <em>50</em>
  <span>OriginY</span>
  <br>
  <input type="range" min="1" data-whatever="OriginX" max="800" value="50" id="sliderOriginX">
  <em>50</em>
  <span>OriginX</span>
</div>

//catch volume update
var volEvents = "change,input";
var volEventsArr = volEvents.split(",");
for(var i = 0;i<volknob.length;i++) {
    for(var k=0;k<volEventsArr.length;k++) {
    volknob[i].addEventListener(volEventsArr[k], function() {
        var cfa = document.getElementsByClassName('watch_televised');
        for (var j = 0; j<cfa.length; j++) {
            cfa[j].volume = this.value / 100;
        }
    });
}
}
Related