user3460707
user3460707

Reputation: 49

How can I add an event listener for multiple buttons with same class name?

I'm building a decision tree in JavaScript. I do not have jQuery available to me for this project.

I would like to be able to have buttons, placed anywhere in the decision tree (Hidden or displayed anywhere on the page), with the same class name. The listener on the JS side would then run a function.

Here is what I am using for and ID based listener. It works well but I need to be able to have multiple buttons with the same class or name available. Although I have seen examples of this, I cannot get it to function properly.

function q1a1() {
var q1a1button = document.getElementById("q1answer1");
        if(q1a1button.addEventListener){
q1a1button.addEventListener("click", function() { q1answer1();}, false);
        } else if(q1a1button.attachEvent){
q1a1button.attachEvent("onclick", function() { q1answer1();});
}
};

if(window.addEventListener){
    window.addEventListener("load", q1a1, false);
        } else if(window.attachEvent){
    window.attachEvent("onload", q1a1);
        } else{
    document.addEventListener("load", q1a1, false);                
}

function q1answer1() {          

//DO SOME STUFF
                                            }

This also needs to work in as many versions of IE as possible. For single class handling I'm using querySelectorAll.

Upvotes: 8

Views: 56679

Answers (5)

SmithBWare89
SmithBWare89

Reputation: 63

Would the simpler way of writing the event delegation function be to add it to the container of the buttons? For example,

// Select Container Element
const questionContainer = document.querySelector(".container");

// Listen For Clicks Within Container
questionContainer.onclick = function (event) {
    // Prevent default behavior of button
    event.preventDefault();

    // Store Target Element In Variable
    const element = event.target;

    // If Target Element Is a Button
    if (element.nodeName === 'BUTTON') {
        // Event Code
    }
}

Upvotes: 1

Paul S.
Paul S.

Reputation: 66404

This answer is a bit overkill, but it should show you ways you could structure your code in a "modern" way even if you're still targeting old browsers

  1. Write code to add event listeners so there is minimal difference between new and old browsers

    var listen = (function () { // will return the handler for use in unlisten
        if (window.addEventHandler) {
            return function (node, type, handler) {
                node.addEventListener(type, handler);
                return handler;
            };
        } else if (window.attachEvent) {
            return function (node, type, handler) {
                var fn = function (e) {
                    if (!e) {
                        e = window.event;
                    }
                    if (!e.target && e.srcElement) {
                        e.target = e.srcElement;
                    }
                    return handler.call(this, e);
                };
                node.attachEvent('on' + type, fn);
                return fn;
            };
        } else {
            throw new Error('Events not supported in this environment');
            // or
         // return function ... node['on' + type] = function () { ... };
        }
    }());
    

    and if you'd like the reverse, too

    var unlisten = (function () { // use handler given by listen
        if (window.removeEventListener) {
            return function (node, type, handler) {
                node.removeEventListener(type, handler);
            };
        } else if (window.detachEvent) {
            return function (node, type, handler) {
                node.detachEvent('on' + type, handler);
            };
        } else {
            throw new Error('Events not supported in this environment');
            // or
         // return function ... node['on' + type] = null;
        }
    }());
    
  2. Write your click handler

    function clickHandler(e) {
        // do stuff
    }
    
  3. Wrap your click handler in a function to choose only clicks on buttons with the right class

    function wrappedClickHandler(e) {
        var tokens, i;
        if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'BUTTON') {
            return;
        }
        tokens = (e.target.className || '').split(' ');
        for (i = 0; i < tokens.length; ++i) {
            if (tokens[i] === 'theClassTokenWeWant') {
                return clickHandler.call(this, e);
                // or
             // return clickHandler.call(e.target, e);
            }
        }
    }
    
  4. Add this as a listener to a common ancestor node

    var h = listen(document, 'click', wrappedClickHandler);
    // .. later, if desired
    unlisten(document, 'click', h);
    

Upvotes: 1

ndugger
ndugger

Reputation: 7551

var buttons = document.querySelectorAll(".MyClassName");
var i = 0, length = buttons.length;
for (i; i < length; i++) {
    if (document.addEventListener) {
        buttons[i].addEventListener("click", function() {
            // use keyword this to target clicked button
        });
    } else {
        buttons[i].attachEvent("onclick", function() {
            // use buttons[i] to target clicked button
        });
    };
};

Upvotes: 1

Greg Burghardt
Greg Burghardt

Reputation: 18938

What you are really looking for is JavaScript Event Delegation. In your case, you have BUTTON elements, which I'm going to assume are <button> tags. Now you want to know when one of those buttons was clicked and then run a function:

if (document.addEventListener) {
    document.addEventListener("click", handleClick, false);
}
else if (document.attachEvent) {
    document.attachEvent("onclick", handleClick);
}

function handleClick(event) {
    event = event || window.event;
    event.target = event.target || event.srcElement;

    var element = event.target;

    // Climb up the document tree from the target of the event
    while (element) {
        if (element.nodeName === "BUTTON" && /foo/.test(element.className)) {
            // The user clicked on a <button> or clicked on an element inside a <button>
            // with a class name called "foo"
            doSomething(element);
            break;
        }

        element = element.parentNode;
    }
}

function doSomething(button) {
    // do something with button
}

Anywhere on the page that a <button class="foo">...</button> element appears, clicking it, or any HTML tag inside of it, will run the doSomething function.

Update: Since Event Delegation is used, only a single click handler is registered on the document object. If more <button>s are created as a result of an AJAX call, you don't have to register click handlers on those new <button>s since we take advantage of the click event bubbling up from the element the user clicked on to the document object itself.

Upvotes: 9

carter
carter

Reputation: 5452

If you don't have jquery:

if (document.body.addEventListener){
    document.body.addEventListener('click',yourHandler,false);
}
else{
    document.body.attachEvent('onclick',yourHandler);//for IE
}

function yourHandler(e){
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.className.match(/keyword/))
    {
        //an element with the keyword Class was clicked
    }
}

If you use a cross browser library like jquery:

HTML:

<div class="myClass">sample</div>
<div class="myClass">sample 2</div>

JS:

function theFuncToCall(event){
  //func code
}

$(document).on('click', '.myClass', theFuncToCall);

Upvotes: 4

Related Questions