4

I know already about event delegation by jQuery. However, How can I do same thing with pure Javascript without jQuery.

Although I attached change event on body or the top element(div), change event is not triggered when value of input element in body or top element is changed...

How can I do this?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Younghun Jung
  • 329
  • 5
  • 17

3 Answers3

1

You can just listen for the event on one element (in this case elSelector) and then only execute the event when the actual target fits a selector in that element.

function on(elSelector, eventName, selector, fn) {
    var element = document.querySelector(elSelector);

    element.addEventListener(eventName, function(event) {
        var possibleTargets = element.querySelectorAll(selector);
        var target = event.target;

        for (var i = 0, l = possibleTargets.length; i < l; i++) {
            var el = target;
            var p = possibleTargets[i];

            while(el && el !== element) {
                if (el === p) {
                    return fn.call(p, event);
                }

                el = el.parentNode;
            }
        }
    });
}

In the example below you can see that it also works with dynamic elements!

on("#inputs", "change", ".event", (target, evt) => console.log(target.target));




function on(elSelector, eventName, selector, fn) {
  var element = document.querySelector(elSelector);

  element.addEventListener(eventName, function(event) {
    var possibleTargets = element.querySelectorAll(selector);
    var target = event.target;

    for (var i = 0, l = possibleTargets.length; i < l; i++) {
      var el = target;
      var p = possibleTargets[i];

      while (el && el !== element) {
        if (el === p) {
          return fn.call(p, event);
        }

        el = el.parentNode;
      }
    }
  });
}

/** random code for the button to add more inputs **/

let i = 7;

document.querySelector("#b").addEventListener("click", () => {
  document.querySelector("#inputs").innerHTML += i + ` <input type="text" class="event"> <br>`;
  i++;
});
<div id="inputs">
  1 <input type="text" class="event"> <br>
  2 <input type="text" class=""> <br>
  3 <input type="text" class="event"> <br>
  4 <input type="text" class=""> <br>
  5 <input type="text" class="event"> <br>
  6 <input type="text" class=""> <br>
</div>

<br><br>
<button id="b">Add another input</button>
Luca Kiebel
  • 9,790
  • 7
  • 29
  • 44
0

Let's define your event function:

function(event) doSomething{
    //Your code
}

Let's get all the input tags inside your body:

var inputs = document.getElementsByTagName('input');

Now, let's iterate them and attach the event:

for (var inputIndex = 0; inputIndex < inputs.length; inputIndex++) {
    inputs.addEventListener('change', doSomething);
}
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • 1
    However, If some input elements are created dynamically, those input elements can not listen 'change' event. – Younghun Jung Jul 19 '18 at 09:38
  • @YounghunJung you can achieve that by listening to the DOMSubtreeModified event and handle the changes accordingly, see here: https://developer.mozilla.org/en-US/docs/Web/Events/DOMSubtreeModified – Lajos Arpad Jul 19 '18 at 09:56
  • @YounghunJung or you can use the MutationObserver API for this purpose, see here: https://davidwalsh.name/detect-node-insertion – Lajos Arpad Jul 19 '18 at 09:57
0

Tl;DR: you probably need to listen on the input event instead.


The reason you are probably not seeing the event being triggered, is because it is triggered: "...when the element loses focus after its value was changed." Source: MDN.

What you probably need to listen to, is the input event instead which "fires when the value has been changed." Source: MDN

Here's an event listener attached to the <body> HTML element which captures all the 'bubbled' input and change events (see how the input event is triggered immediately whereas the change event requires that the input element loses focus, e.g. when pressing Tab):

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Input Event Delegation</title>
  </head>
  <body>
    <input name="email" type="email" />
    <input name="name" type="text" />
    <script>
      document.body.addEventListener("input", (e) => {
        console.log("type:", e.type, "value:", e.target.value);
      });
      document.body.addEventListener("change", (e) => {
        console.log("type:", e.type, "value:", e.target.value);
      });
    </script>
  </body>
</html>
Kostas Minaidis
  • 4,681
  • 3
  • 17
  • 25