Adding Multiple Event Listeners to One Element

adding multiple event listeners to one element

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>

Can multiple event listeners/handlers be added to the same element using Javascript?

You can do how ever you want it to do. They don't have to be together, it depends on the context of the code. Of course, if you can put them together, then you should, as this probably makes the structure of your code more clear (in the sense of "now we are adding all the event handlers").

But sometimes you have to add event listeners dynamically. However, it is unnecessary to test multiple times whether you are dealing with IE or not.

Better would be to abstract from this and test only once which method is available when the page is loaded. Something like this:

var addEventListener = (function() {
if(document.addEventListener) {
return function(element, event, handler) {
element.addEventListener(event, handler, false);
};
}
else {
return function(element, event, handler) {
element.attachEvent('on' + event, handler);
};
}
}());

This will test once which method to use. Then you can attach events throughout your script with:

addEventListener(window, 'load',videoPlayer);
addEventListener(window, 'load',somethingelse);

Binding multiple events to a listener (without JQuery)?

In POJS, you add one listener at a time. It is not common to add the same listener for two different events on the same element. You could write your own small function to do the job, e.g.:

/* Add one or more listeners to an element
** @param {DOMElement} element - DOM element to add listeners to
** @param {string} eventNames - space separated list of event names, e.g. 'click change'
** @param {Function} listener - function to attach for each event as a listener
*/
function addListenerMulti(element, eventNames, listener) {
var events = eventNames.split(' ');
for (var i=0, iLen=events.length; i<iLen; i++) {
element.addEventListener(events[i], listener, false);
}
}

addListenerMulti(window, 'mousemove touchmove', function(){…});

Hopefully it shows the concept.

Edit 2016-02-25

Dalgard's comment caused me to revisit this. I guess adding the same listener for multiple events on the one element is more common now to cover the various interface types in use, and Isaac's answer offers a good use of built–in methods to reduce the code (though less code is, of itself, not necessarily a bonus). Extended with ECMAScript 2015 arrow functions gives:

function addListenerMulti(el, s, fn) {
s.split(' ').forEach(e => el.addEventListener(e, fn, false));
}

A similar strategy could add the same listener to multiple elements, but the need to do that might be an indicator for event delegation.

Adding Multiple Event Listeners in Chrome Extension

Problem was fixed. Rather than adding an event listener, I had to add the .onclick event on the creation of the element.

How to add multiple event listeners for the same react component?

You could create a custom hook like this:

import { useEffect } from 'react'

export const useResizeScroll = callback => {
useEffect(() => {
window.addEventListener('resize scroll', callback);
return () => window.removeEventListener('resize scroll', callback);
}, [callback]);
};

Then implement it in your component like this:

const MyComponent = () => {
useResizeScroll(handleVisible)

function handleVisible() { ... }

return (...)
}

Note:

This will required you to move over to a hooks implementation of your component.

So if you were using this.state = { ... }, you'll need to go learn how to make use of React's useState hook: React useState Hook

UPDATE:

If you want the hook to be more flexible, like selecting what event listeners you want the component to hook onto, then you could do this:

export const useResizeScroll = (eventListener, callback) => {
useEffect(() => {
window.addEventListener(eventListener, callback);
return () => window.removeEventListener(eventListener, callback);
}, [callback]);
};

And then implement it like this:

useResizeScroll('resize scroll', handleVisible)

More Advanced Use Case:

You could also improve your custom hook by making use of React Context. Here's an example of implementing a hook that keeps track of your window width.

import React, { createContext, useContent, useEffect, useState } from 'react'

const ViewportContext = createContext({ width: window.innerWidth })

export const ViewportProvider = ({ children }) => {
const [width, setWidth] = useState(window.innerWidth)

function handleResize() {
setWidth(window.innerWidth)
}

useEffect(() => {
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])

return (
<ViewportContext.Provider value={{ width }}>
{children}
</ViewportContext.Provider>
)
}

export const useViewport = () => {
const { width } = useContext(ViewportContext)
return { width }
}

Then you can use it in any component like this:

const { width } = useViewport()

This should provide you with enough information to build a custom hook to match your use case.

How to addEventListener to multiple elements in a single line

Well, if you have an array with the elements you could do:

let elementsArray = document.querySelectorAll("whatever");

elementsArray.forEach(function(elem) {
elem.addEventListener("input", function() {
//this function does stuff
});
});


Related Topics



Leave a reply



Submit