Sergi
Sergi

Reputation: 1240

Javascript DOM manipulation, Each click creates a new li element

I have an app with a few buttons, and every button has an element, button one has a "banana" and button 2 has an "apple", when the user clicks on those buttons, a new li element should be added to a list. Here is a JSFiddle with an example of the problem I'm running into:

https://jsfiddle.net/ejha3q94/

Only 1 li is created with every click and the elements are just added on that same li.

 var newElement = document.createElement("li");
 var newElText = document.createTextNode ("");

 document.getElementById("itemOne").addEventListener("click", function() {
  newElText = document.createTextNode("Banana");
   document.getElementById("list").appendChild(newElement).appendChild(newElText);

 });

 document.getElementById("itemTwo").addEventListener("click", function() {
  newElText = document.createTextNode("Apple");
    document.getElementById("list").appendChild(newElement).appendChild(newElText);

  });

How can I make it so every click is a new li element using only Javascript?

Upvotes: 2

Views: 2146

Answers (4)

guest271314
guest271314

Reputation: 1

You can use document.querySelectorAll() with selector "[id^=item]"; iterate elements using for..of loop; create the elements within click event handler; append #text node to li element using HTMLElement.dataset before appending li element to ul element

<div id="itemOne" data-fruit="Banana">
  🍌
</div>

<div id="itemTwo" data-fruit="Apple">
  🍎
</div>
<ul id="list"> </ul>
<script>
var list = document.getElementById("list");
for (el of document.querySelectorAll("[id^=item]")) {
  el.addEventListener("click", function() {
    list.appendChild(document.createElement("li"))
    .textContent = this.dataset.fruit;
  })
}
</script>

jsfiddle https://jsfiddle.net/ejha3q94/4/

Upvotes: 2

Mulan
Mulan

Reputation: 135357

You can't reuse elements by reassigning them. You have to create a new element each time you wish to insert a new element into the DOM.

This solution creates a generic function addItem for your procedure. You can see all the element creation and DOM manipulation in one place.

// element references
var list = document.getElementById('list');
var appleBtn = document.getElementById('apple');
var bananaBtn = document.getElementById('banana');

// DOM manipulating function
function addItem(listElem, text) {
  var li = document.createElement('li');
  var textNode = document.createTextNode(text);
  listElem.appendChild(li).appendChild(textNode);
}

// event listeners
appleBtn.addEventListener('click', function(event) {
  addItem(list, 'apple');
});
bananaBtn.addEventListener('click', function(event) {
  addItem(list, 'banana');
});
    
    
<ul id="list"></ul>

<button id="apple">Apple</button>
<button id="banana">Banana</button>

But even repeating addItem(list, *) can get repetitious too. Plus, we don't necessarily need one event listener per button. Wouldn't it be nice if we could just use a single event listener to handle all of the cases?

The solution below uses a data-* attribute to store each button's contribution to the list. Then, using event delegation we handle all buttons with a single event listener (function).

// element references
var list = document.getElementById('list');
var buttons = document.getElementById('buttons');

// single #buttons event delegate
buttons.addEventListener('click', function(event) {
  // event.target contains the element that was clicked
  var item = event.target.dataset.item;
  if (item === undefined) return false;
  var li = document.createElement('li');
  var textNode = document.createTextNode(item);
  list.appendChild(li).appendChild(textNode);
});
<ul id="list"></ul>

<div id="buttons">
  <button data-item="apple">Apple</button>
  <button data-item="banana">Banana</button>
  <button data-item="orange">Orange</button>
  <button data-item="grape">Grape</button>
  <button data-item="plum">Plum</button>
</div>

Upvotes: 4

seahorsepip
seahorsepip

Reputation: 4819

Make sure that var newElement and newElText is created or cloned on every click instead of referenced: https://jsfiddle.net/ejha3q94/2/

Otherwise it won't create a new list element but modifies the existing list element every time.

document.getElementById("itemOne").addEventListener("click", function() {
    var newElement = document.createElement("li");
    var newElText = document.createTextNode("Banana");
    document.getElementById("list").appendChild(newElement).appendChild(newElText);
});

document.getElementById("itemTwo").addEventListener("click", function() {
    var newElement = document.createElement("li");
    var newElText = document.createTextNode("Apple");
    document.getElementById("list").appendChild(newElement).appendChild(newElText);
});

Upvotes: 2

Oriol
Oriol

Reputation: 288480

There can only be a single newElText node. If you append it multiple times, it will just be moved. You should clone it manually:

var newElement = document.createElement("li");
var list = document.getElementById("list");
document.getElementById("itemOne").addEventListener("click", function() {
  var newElText = document.createTextNode("Banana");
  list.appendChild(newElement.cloneNode(false)).appendChild(newElText);
});
document.getElementById("itemTwo").addEventListener("click", function() {
  var newElText = document.createTextNode("Apple");
  list.appendChild(newElement.cloneNode(false)).appendChild(newElText);
});
<div id="itemOne">🍌</div>
<div id="itemTwo">🍎</div>
<ul id ="list"></ul>

Upvotes: 0

Related Questions