javascripthtmldom-events

adding multiple event listeners to one element


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!


Solution

  • Maybe you can use a helper function like this:

    // events and args should be of type Array
    function addMultipleListeners(element,events,handler,useCapture,args){
      if (!(events instanceof Array)){
        throw 'addMultipleListeners: '+
              'please supply an array of eventstrings '+
              '(like ["click","mouseover"])';
      }
      //create a wrapper to be able to use additional arguments
      var handlerFn = function(e){
        handler.apply(this, args && args instanceof Array ? args : []);
      }
      for (var i=0;i<events.length;i+=1){
        element.addEventListener(events[i],handlerFn,useCapture);
      }
    }
    
    function handler(e) {
      // do things
    };
    
    // usage
    addMultipleListeners(
        document.getElementById('first'),
        ['touchstart','click'],
        handler,
        false);
    

    [Edit nov. 2020] This answer is pretty old. The way I solve this nowadays is by using an actions object where handlers are specified per event type, a data-attribute for an element to indicate which action should be executed on it and one generic document wide handler method (so event delegation).

    const firstElemHandler = (elem, evt) =>
      elem.textContent = `You ${evt.type === "click" ? "clicked" : "touched"}!`;
    const actions = {
      click: {
        firstElemHandler,
      },
      touchstart: {
        firstElemHandler,
      },
      mouseover: {
        firstElemHandler: elem => elem.textContent = "Now ... click me!",
        outerHandling: elem => {
          console.clear();
          console.log(`Hi from outerHandling, handle time ${
            new Date().toLocaleTimeString()}`);
        },
      }
    };
    
    Object.keys(actions).forEach(key => document.addEventListener(key, handle));
    
    function handle(evt) {
      const origin = evt.target.closest("[data-action]");
      return origin &&
        actions[evt.type] &&
        actions[evt.type][origin.dataset.action] &&
        actions[evt.type][origin.dataset.action](origin, evt) ||
        true;
    }
    [data-action]:hover {
      cursor: pointer;
    }
    <div data-action="outerHandling">
      <div id="first" data-action="firstElemHandler">
        <b>Hover, click or tap</b>
      </div>
      this is handled too (on mouse over)
    </div>