Search code examples
javascripthtmlcss

AddEventListener on all created li elements


So I have a simple script that adds "li" elements to the "ul" and assigns them a class. Now I want to change the class of "li" item on click event.

Here is the HTML:

<form class="form">
<input id="newInput" type="text" placeholder="Dodaj pozycję">
<button id="createNew" type="button">Dodaj</button>
</form>
<h2>Moja lista:</h2>
<div class="listBg">
<ul id="list">
</ul>
</div>
<button id="deleteAll" type="button">Wyczyść</button>

And JS:

function addItem() {
    var myList = document.getElementById("list"); // get the main list ("ul")
    var newListItem = document.createElement("li"); //create a new "li" element
    var itemText = document.getElementById("newInput").value; //read the input value from #newInput
    var listText = document.createTextNode(itemText); //create text node with calue from input
    newListItem.appendChild(listText); //add text node to new "li" element
    if (itemText === "") { // if input calue is empty
        alert("Pole nie może być puste"); // show this alert
    } else { // if it's not empty
        var x = document.createElement("span"); // create a new "span" element
        x.innerText = "X"; // add inner text to "span" element
        x.className = "closer"; // add class to "span" element
        myList.appendChild(newListItem); // add created "li" element to "ul"
        newListItem.className = "item"; // add class to new "li" element
        newListItem.appendChild(x); // add a "span" to new "li" element
        var itemText = document.getElementById("newInput"); // read current input value
        itemText.value = ""; // set current input calue to null
    }
};

I was thinking something like this should do the trick, but it's not working:

function itemDone() {
    var listItems = document.querySelectorAll("li");
    var i;
    for (i = 0; i < listItems.length; i++) {
    listItem[i].className = "itemDone";
};
};

var item = document.getElementsByClassName("item");
item.addEventListener("click", itemDone);

I'm fairly new to javascript so I would appreciate some explanation with the answer.


Solution

  • Use event delegation for the dynamically created elements. With this, you only need one event listener on the ul#list and it will work for all elements you dynamically attach to it:

    document.getElementById("list").addEventListener("click",function(e) {
      if (e.target && e.target.matches("li.item")) {
        e.target.className = "foo"; // new class name here
        }
    });
    

    Here's a simplified example so you can see what happens with the code:

    function addItem(i) {
      var li = document.createElement('li');
      li.appendChild(document.createTextNode(i));
      li.className = 'item';
      document.getElementById('list').appendChild(li);
    }
    
    var counter = 2;
    document.getElementById('btn').addEventListener('click', function() {
      addItem(counter++);
    });
    
    document.getElementById("list").addEventListener("click", function(e) {
      if (e.target && e.target.matches("li.item")) {
        e.target.className = "foo"; // new class name here
        alert("clicked " + e.target.innerText);
      }
    });
    <ul id="list">
      <li class="item">1</li>
    </ul>
    
    <button id="btn">
      add item
    </button>