Ari Seyhun
Ari Seyhun

Reputation: 12531

Attatch event listener to all elements by selector in JavaScript from document

In jQuery, you can add an event listener to the document using .on() with a selector as the 2nd argument to listen to all events sent to specific elements, even if the HTML is dynamically changes.

It looks something like this:

$(document).on('change', "input:checkbox", onCheckboxChange);

How can I do the same thing in pure modern JavaScript which works even if HTML is dynamically changed?

I understand I could do something like document.querySelector('input:checkbox') and apply an event listener to each individual element, but if a new input:checkbox is added, then it will not have the same event listener that the other input's have.

Upvotes: 2

Views: 1972

Answers (2)

T.J. Crowder
T.J. Crowder

Reputation: 1075537

You'd attach the listener to document (that part's the same) accepting the event parameter (let's call it e) and use Element#closest on e.target to determine whether the event passed through an element matching a selector:

document.addEventListener("change", function(e) {
    var target = e.target.closest("input[type=checkbox]");
    if (target) {
        // It matches
        console.log("change", target.checked);
    }
});

Live Example (including adding a matching element after the fact):

document.addEventListener("change", function(e) {
    var target = e.target.closest("input[type=checkbox]");
    if (target) {
        // It matches
        console.log("change", target.checked);
    }
});
setTimeout(function() {
  document.body.insertAdjacentHTML(
    "beforeend",
    "<div><label><input type='checkbox'> Or tick me");
}, 800);
<div>
  <label>
    <input type="checkbox"> Tick me
  </label>
</div>

Element#closest is fairly new, but present in all modern browsers (so, not IE). You can polyfill it on IE, though; see the linked MDN article for a polyfill.

You can give yourself a utility function that does effectively what jQuery's delegating version of on does quite easily:

function addHandler(element, selector, eventName, handler) {
    if (typeof eventName === "undefined") {
        // No selector, swap things around
        eventName = selector;
        selector = undefined;
    }
    element.addEventListener(eventName, function(e) {
        var currentTarget = e.currentTarget;
        if (selector) {
            currentTarget = e.target.closest(selector);
            if (!currentTarget) {
                // Not a match, ignore
                return;
            }
        }
        // Note we use `currentTarget` as this during the call
        // Sadly, `currentTarget` on the actual event object is
        // read-only. We could create a synthetic event object
        // like jQuery does and set it on that instead.
        // I didn't do that here, but it's easy enough.
        return handler.call(currentTarget, e);
    });
    return element;
}

// Usage
addHandler(document, "input[type=checkbox]", "change", function(e) {
    console.log("changed", this.checked);
});
setTimeout(function() {
    document.body.insertAdjacentHTML(
        "beforeend",
        "<div><label><input type='checkbox'> Or tick me");
}, 800);
<div>
  <label>
    <input type="checkbox"> Tick me
  </label>
</div>

Upvotes: 4

Mayur Shingare
Mayur Shingare

Reputation: 306

First I am creating a checkbox and then appending it to Dom And them adding event listener to it by its Id.

var checkbox = document.createElement('input');
checkbox.type = "checkbox";
checkbox.name = "name";
checkbox.value = "value";
checkbox.id = "id";

document.body.appendChild(checkbox); 

var abc = document.getElementById('id');

abc.addEventListener("click", function () {
 alert('click');
});

Upvotes: -1

Related Questions