Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a pure Javascript way to apply one function to multiple element's events?

Tags:

javascript

dom

I want to bind a single function to multiple events using pure Javascript.

In jQuery I would use:

$('.className').click(function(e){ //do stuff });

So using pure JS I tried:

document.getElementsByClassName('className').onclick = function(e){ //do stuff };

Which doesn't work, because getElementsByClassName returns an array, not a DOM object.

I can loop through the array, but this seems overly verbose and like it shouldn't be necessary:

var topBars = document.getElementsByClassName('className');
for(var i = 0; i < topBars.length; i++){
    topBars[i].onclick = function(e){ //do stuff };
}

Is there a standard way to accomplish this with pure Javascript?

like image 506
James G. Avatar asked Jan 11 '15 22:01

James G.


People also ask

How do you apply an event listener to multiple elements?

Adding event listener to multiple elements To add the event listener to the multiple elements, first we need to access the multiple elements with the same class name or id using document. querySelectorAll() method then we need to loop through each element using the forEach() method and add an event listener to it.

Can I have multiple event listeners Javascript?

You can add many event handlers to one element. You can add many event handlers of the same type to one element, i.e two "click" events. You can add event listeners to any DOM object not only HTML elements. i.e the window object.

Can you have two event listeners?

We can add multiple event listeners for different events on the same element. One will not replace or overwrite another. In the example above we add two extra events to the 'button' element, mouseover and mouseout.

Can you add multiple addEventListener?

Unfortunately, you can't pass in multiple events to a single listener like you might in jQuery and other frameworks. For example, you cannot do this: document. addEventListener('click mouseover', function (event) { // do something... }, false);


2 Answers

You could add the event handler to the parent element, and then determine whether one of the children elements with the desired classname is clicked:

var parent = document.getElementById('parent');
parent.addEventListener('click', function (e) {
    if ((' ' + e.target.className + ' ').indexOf(' item ') !== -1) {
        // add logic here
        console.log(e.target);
    }
});

Example Here

or...

var parent = document.getElementById('parent');
parent.addEventListener('click', function (e) {
    Array.prototype.forEach.call(parent.querySelectorAll('.item'), function (el) {
        if (el === e.target) {
            // add logic here
            console.log(e.target);
        }
    });
});

Example Here


The above snippets will only work when you are clicking on the element with the specified class. In other words, it won't work if you click on that given element's child. To work around that, you could use the following:

var parent = document.getElementById('parent');
parent.addEventListener('click', function (e) {
    var target = e.target; // Clicked element
    while (target && target.parentNode !== parent) {
        target = target.parentNode; // If the clicked element isn't a direct child
        if (!target) { return; } // If element doesn't exist
    }
    if ((' ' + target.className + ' ').indexOf(' item ') !== -1){
        // add logic here
        console.log(target);
    }
});

Alternative Example

var parent = document.getElementById('parent');

parent.addEventListener('click', function (e) {
    var target = e.target; // Clicked element
    while (target && target.parentNode !== parent) {
        target = target.parentNode; // If the clicked element isn't a direct child
        if (!target) { return; } // If element doesn't exist
    }
    Array.prototype.forEach.call(parent.querySelectorAll('.item'), function (el) {
        if (el === target) {
            // add logic here
            console.log(target);
        }
    });
});

Example Here

like image 166
Josh Crozier Avatar answered Sep 28 '22 05:09

Josh Crozier


As a hack, where the DOM is implemented using a prototype inheritance model (most browsers but not all), you can add an iterator to the NodeList constructor:

if (NodeList && NodeList.prototype && !NodeList.prototype.forEach) {
  NodeList.prototype.forEach = function(callback, thisArg) {
    Array.prototype.forEach.call(this, callback, thisArg)
  }
} 

Then:

document.getElementsByClassName('item').forEach(function(el){
  el.addEventListener('click', someFn, false);
})

or

document.querySelectorAll('.item').forEach(function(el){
  el.addEventListener('click', someFn, false);
})

Of course you shouldn't do this in production on the web (don't mess with host objects and all that), but wouldn't it be nice if it was OK? Or iterators were added to DOM lists and collections?

like image 29
RobG Avatar answered Sep 28 '22 07:09

RobG