1

I am developing a chat app, and my issue raises when I try to add new elements to a list of chat rooms, see them, and interact with them without reloading the page.

I am adding HTML elements to a list with JavaScript.

Then I try to querySelectorAll elements in the list.

The elements that were loaded from the server on page load can be selected.

But the newly created elements with JavaScript don't seem to get selected.

Here is how I try to select my elements and, when clicked, execute some code for each of them:

 document.querySelectorAll('.select-room').forEach(p => {
        p.onclick = () => { <my code here> })

The elements that are already on the list get selected just fine and my code executes alright.

But when I add a new element with JavaScript. Even though the HTML of it looks just the same as the HTML of other existing elements, including the class by which it gets selected, the result is I can only select those after reloading the page.

Is there a way I can listen for changes made to the DOM, so that after adding with JavaScript new elements with the same class, they will be selected like the others without having to reload the page?

Here is a Minimal, Complete, Reproducible Example of my problem:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>mcr problem</title>
    <script>
      document.addEventListener("DOMContentLoaded", () => {
        // Clicking element in the list shows an alert.
        document.querySelectorAll(".clickable").forEach(li => {
          li.onclick = () => {alert("interaction!")};
        });

        // Clicking on button adds new element to the list
        document.querySelector("#add-btn").onclick = () => {
          newLi = document.createElement("li");
          newLi.classList.add("clickable");
          newLi.innerHTML = "New Item";
          document.querySelector("#parent-list").append(newLi);
        };
      });
    </script>
  </head>
  <body>
    <h1>List of items</h1>
    <button id="add-btn">Add</button>
    <ul id="parent-list">
      <li class="clickable" id="post-1">Item 1</li>
      <li class="clickable" id="post-2">Item 2</li>
      <li class="clickable" id="post-3">Item 3</li>
    </ul>
  </body>
</html>
  • 2
    Please provide a [Minimal, Reproducible Example](/help/minimal-reproducible-example) so we can diagnose the problem. – D. Pardal May 31 '20 at 11:19
  • Does this answer your question? [What is DOM Event delegation?](https://stackoverflow.com/questions/1687296/what-is-dom-event-delegation) – Arun A S May 31 '20 at 11:26
  • Thank you @D.Pardal , I have edited my question and added the example. You can see how a new element is added to the list by clicking on a button. After that, how can this new element behave like the others? Basically do something when clicked on. Here I just used an alert when clicking a list element to make my example minimal. – Juan Carlos Marcos Prieto Jun 01 '20 at 05:33
  • @JuanCarlosMarcosPrieto You can check my answer, also mentioned the reason why it was not working – Aditya toke Jun 01 '20 at 05:46

1 Answers1

1

Reasons why alert was not getting called DOMContentLoaded
This event triggers when the DOM tree forms i.e. the script is loading. Scripts start to run before all the resources like images, CSS, and JavaScript loads. You can attach this event either to the window or the document objects
and at that time the query selector has only 3 node of class .clickable so it apply only on those 3 elements.
In javascript DOMNodeInserted
It fires when the script inserts a new node in the DOM tree using appendChild(), replaceChild(), insertBefore(), etc.

document.addEventListener("DOMContentLoaded", () => {
  document.querySelectorAll(".clickable").forEach((li) => {
    li.onclick = () => commonAlertMethod();
  });
  // Clicking on button adds new elemnt to the list
  document.querySelector("#add-btn").onclick = () => {
    newLi = document.createElement("li");
    newLi.classList.add("clickable");
    newLi.innerHTML = "New Item";
    document.querySelector("#parent-list").append(newLi);
  };
});

document.addEventListener("DOMNodeInserted", () => {
  // Clicking element in the list shows an alert.
  document.querySelectorAll(".clickable").forEach((li) => {
    li.onclick = () => commonAlertMethod();
  });
});

function commonAlertMethod() {
  alert("interaction!");
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>List of items</h1>
    <button id="add-btn">Add</button>
    <ul id="parent-list">
      <li class="clickable" id="post-1">Item 1</li>
      <li class="clickable" id="post-2">Item 2</li>
      <li class="clickable" id="post-3">Item 3</li>
    </ul>
</body>
</html>
Aditya toke
  • 355
  • 2
  • 12