While working with browser events, I've started incorporating Safari's touchEvents for mobile devices. I find that addEventListener
s are stacking up with conditionals. This project can't use JQuery.
A standard event listener:
/* option 1 */
window.addEventListener('mousemove', this.mouseMoveHandler, false);
window.addEventListener('touchmove', this.mouseMoveHandler, false);
/* option 2, only enables the required event */
var isTouchEnabled = window.Touch || false;
window.addEventListener(isTouchEnabled ? 'touchmove' : 'mousemove', this.mouseMoveHandler, false);
JQuery's bind
allows multiple events, like so:
$(window).bind('mousemove touchmove', function(e) {
//do something;
});
Is there a way to combine the two event listeners as in the JQuery example? ex:
window.addEventListener('mousemove touchmove', this.mouseMoveHandler, false);
Any suggestions or tips are appreciated!
Some compact syntax that achieves the desired result, POJS:
"mousemove touchmove".split(" ").forEach(function(e){
window.addEventListener(e,mouseMoveHandler,false);
});
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.
"It is not common to add the same listener for two different events on the same element."
Sometimes (greener) devs need to hear this to know they're doing it right :)
Cleaning up Isaac's answer:
['mousemove', 'touchmove'].forEach(function(e) {
window.addEventListener(e, mouseMoveHandler);
});
EDIT
ES6 helper function:
function addMultipleEventListener(element, events, handler) {
events.forEach(e => element.addEventListener(e, handler))
}
ES2015:
let el = document.getElementById("el");
let handler =()=> console.log("changed");
['change', 'keyup', 'cut'].forEach(event => el.addEventListener(event, handler));
for...of
loop
For me; this code works fine and is the shortest code to handle multiple events with same (inline) functions.
var eventList = ["change", "keyup", "paste", "input", "propertychange", "..."];
for(event of eventList) {
element.addEventListener(event, function() {
// your function body...
console.log("you inserted things by paste or typing etc.");
});
}
I have a simpler solution for you:
window.onload = window.onresize = (event) => {
//Your Code Here
}
I've tested this an it works great, on the plus side it's compact and uncomplicated like the other examples here.
One way how to do it:
const troll = document.getElementById('troll'); ['mousedown', 'mouseup'].forEach(type => { if (type === 'mousedown') { troll.addEventListener(type, () => console.log('Mouse is down')); } else if (type === 'mouseup') { troll.addEventListener(type, () => console.log('Mouse is up')); } }); img { width: 100px; cursor: pointer; }
if (type === 'mousedown')
?!?!
type
is the parameter of forEach()
. So without the array and without the forEach function, type
would not be defined.
troll.addEventListener('mousedown', () => console.log('Mouse is down'));
. Why do you need a forEach
if you're going to check for each event type and attach a different event handler to it?! The whole point of using a forEach
in this case is to attach the same event handler to multiple events, obviously.
AddEventListener take a simple string that represents event.type. So You need to write a custom function to iterate over multiple events.
This is being handled in jQuery by using .split(" ") and then iterating over the list to set the eventListeners for each types
.
// Add elem as a property of the handle function
// This is to prevent a memory leak with non-native events in IE.
eventHandle.elem = elem;
// Handle multiple events separated by a space
// jQuery(...).bind("mouseover mouseout", fn);
types = types.split(" ");
var type, i = 0, namespaces;
while ( (type = types[ i++ ]) ) { <-- iterates thru 1 by 1
You can also use prototypes to bind your custom function to all elements
Node.prototype.addEventListeners = function(eventNames, eventFunction){
for (eventName of eventNames.split(' '))
this.addEventListener(eventName, eventFunction);
}
Then use it
document.body.addEventListeners("mousedown touchdown", myFunction)
// BAD: One for each event - Repeat code
textarea.addEventListener('keypress', (event) => callPreview);
textarea.addEventListener('change', (event) => callPreview);
// GOOD: One run for multiple events
"keypress change".split(" ").forEach((eventName) => textarea.addEventListener(eventName, callPreview));
Success story sharing
['mousemove', 'touchmove'].forEach(...)
['mousemove', 'touchmove'].forEach(function(event) { window.addEventListener(event, handler);});
would not only be way more readable but also would be much faster not having to split the string and then running a function for each item in the resulting array.