Search code examples
javascriptdom-eventsevent-listenerevent-delegation

Attaching eventListener to dynamic elements in Javascript


I'm making a todo list and I have li and button tags added dynamically when adding a new list item. The button is an x which is supposed to remove the list item. I have tried several things but can't figure out how to make an eventListener for each individual x button and remove the corresponding list item when it is clicked.

The renderTodos function is where all of the dynamically added content is created. I have a data-index set to each button in which I was trying to use to access each button to attach an eventListener on each dynamic button, but I wasn't sure how to implement that. From what I have read there should be a way to do this using the currentTarget or target of the event but I don't understand how that works.

var input = document.querySelector('input[name=todoItem]'),

btnAdd = document.querySelector('button[name=add]'),
btnClear = document.querySelector('button[name=clear]'),
list = document.querySelector('.todo'),
storeList = [];

function renderTodos(){
  var el = document.createElement('li'),
  x = document.createElement('button');
  listLength = storeList.length;
  
  //Set text for remove button
  x.innerHTML = 'x';

  for(var i = 0; i < listLength; i++){
    el.innerHTML = storeList[i];
    list.appendChild(el);
    x.setAttribute('data-index', i);
    el.appendChild(x);
  }

  // check for correct data-index property on x button
}

function addTodos(){
  storeList.push(input.value);

  // Check that input is getting pushed to list array
  console.log(storeList);
  renderTodos();
}


function clearList(){
  // make list empty
  list.innerHTML = '';
  storeList.splice(0, storeList.length);
  //render empty list
  renderTodos();
  
  //Check that list array is empty
  console.log(storeList);
}

btnAdd.addEventListener('click', addTodos);
btnClear.addEventListener('click', clearList);

Everything else on the list works so far I just can't figure out how to implement this eventListener.


Solution

  • You can add a listener to each button using something like:

     x.innerHTML = '';
     x.onclick = function(){
       var node = this.parentNode;
       node.parentNode.removeChild(node);
     };
    

    Or you can keep the renderTodos code as it is and delegate the remove to the parent UL:

    // Add the listener
    list.addEventListener('click', removeItem);
    
    // The listener function
    function removeItem(event) {
      var node = event.target;
    
      // Check that the click came from an X button
      // better to check against a class name though
      if (node.tagName &&
          node.tagName.toLowerCase() == 'button' &&
          node.innerHTML == 'x') {
        node = node.parentNode;
        node.parentNode.removeChild(node);
      }
    }