Search code examples
javascriptappendchildremovechild

Add/remove <li> element from the ul javascript


I am new in JavaScript and still learning various things. Right now i'm stuck with adding and removing li elements from the list. I did the exercise just fine using jQuery, but now have difficulties with the pure JS version of the same task.

The main idea is to add a new li element by clicking on the button, and remove the the element by clicking on the X button right next to it. I have tried using 'this' and other advices mentioned in similar questions here on Stackoverflow, but nothing worked for me. Could you, please, guide me what am I doing wrong?

P.S. the adding function seems to be working in snippet, but console logs error: cannot read property 'addeventlistener' of null.

//declaring the variables
var btn = document.getElementsByClassName('btn');
var list = document.getElementById('list');
var add = document.getElementById('add');

//adding a new element to the list
add.addEventListener('click', function(){
  var newElement = document.createElement('LI');
  list.appendChild(newElement);
  newElement.innerHTML= "I am a new element<button class='btn'>X</button>";
});

//removing the clicked element
btn.addEventListener('click', function(){
  list.parentNode.removeChild(this);
});
ul li {
  decoration: none;
  display: block;
  margin-top: 1em;
  text-align: center;
  font-family:  'Avant Garde', Avantgarde, 'Century Gothic', CenturyGothic, AppleGothic, sans-serif;
  font-size: 18px;
}

#add {
  background-color: black;
  color: white;
  border: none;
  width: 280px;
  font-color: white;
  border-radius: 8px;
  font-size: 16px;
  padding: 15px;
  outline: none;
  text-align: center;
  margin: 20px auto;
  display: block;
}

#add:hover {
  background-color: #28364d;
  color: white;
  border: none;
  outline: none;
}

#add:active {
  position: relative;
  bottom: 2px;
}

.btn{
  margin-left: 10px;
  border-radius: 10px;
  background-color: #000;
  color: white;
  border: none;
  outline: none;
  font-size: 14px;
  font-family: sans-serif;
}

.btn:active {
position: relative;
bottom: 2px;
}
<div>
      <ul id="list">
        <li class="element">I am a new element<button class="btn">X</button></li>
        <li class="element">I am a new element<button class="btn">X</button></li>
        <li class="element">I am a new element<button class="btn">X</button></li>
        <li class="element">I am a new element<button class="btn">X</button></li>
        <li class="element">I am a new element<button class="btn">X</button></li>
      </ul>

    <button id="add">Add an element to the list</button>
</div>


Solution

  • This returns a non-live collection:

    var btn = document.getElementsByClassName('btn');
    

    Which means that it will only contain the objects which exist at the point of the method call. You need to call getElementsByClassName() after the creation of the new li elements, and attach the EventListeners on the invidual buttons. Just remember not to put an EventListener twice on the buttons.

    A nicer solution

    Better yet: do not use getElementsByClassName(), just attach the event handler directly in the function, in which you create the new button. That way, you don't have to worry about pre-existing event handlers:

    add.addEventListener('click', function(){
        var newElement = document.createElement('LI');
        list.appendChild(newElement);
        newElement.innerHTML= "I am a new element<button class='btn'>X</button>";
        newElement.addEventListener('click', function () {
            this.parentNode.removeChild(this);
        });
    });