Sami
Sami

Reputation: 29

Why document.getElementsByClassName does not get the all elements exactly except for the first time?

I have an array with n items that I looped to create n input buttons. Each input button has onclick function typeItem() that adds the clicked Item to a new array typedItem[] and makes that clicked item hidden and give it a new class clicked.

Then I have an upper Button with onclick function undo() which supposed to remove the hidden property and make those clicked items visible again. I used the document.getElementsByClassName method to get the elements but it does not get all clicked elements except for the first time.

When I click more than 5 items randomly and trigger the undo() function, not all elements clicked reappear again. it misses one or more buttons especially from the second time after reloading the page...

Why that happens and how to fix it?? ...

var arr = ["can", "san", "tan", "ban", "man", "yan", "fan", "van", "zan", "ran", "xan", "gan"];
for (i = 0; i < arr.length; i++) {
  document.getElementById('dv').innerHTML += "<input type='button' class='button' onclick='typeItem(this.value,this.id)' value='" + arr[i] + "'>";
  document.getElementsByClassName('button')[i].id = "id" + i;
}

var typedItems = [];

function typeItem(val, idd) {
  document.getElementById(idd).style.visibility = 'hidden';
  document.getElementById(idd).classList.add('clicked');
  typedItems.push(val);
}

function undo() {
  for (t = 0; t < typedItems.length; t++) {
    document.getElementsByClassName("clicked")[t].style.visibility = 'visible';
  }
  typedItems = [];
};
* {
  text-align: center
}

input,
button {
  margin: 3px;
  width: 23%;
  height: 50px;
}
<button style="background:orange" onclick="undo()">UnDo Button</button>

<br><br><br>

<p id="dv"></p>

<br>
<p id="dvv"></p>

Upvotes: 1

Views: 1517

Answers (3)

Saadi Toumi Fouad
Saadi Toumi Fouad

Reputation: 2829

Here you go

var arr = ["can","san","tan","ban","man","yan","fan","van","zan","ran","xan","gan"],
  container = document.querySelector("#b_container"),
  buttons = [];

arr.forEach(function(elem) {
  container.innerHTML += `<button>${elem}</button>`;
});

buttons = document.querySelectorAll("button");

document.querySelector("#b_container").onclick = function(e) {
  if(e.target.nodeName === "BUTTON") {
    e.target.className = "b_hidden";
  }
}

document.querySelector("#b_undo").onclick = function() {
  buttons.forEach(function(elem) {
    elem.className = "";
  });
}
#b_undo {
  background-color: orange;
  margin-bottom: 40px;
}
.b_hidden {
  visibility: hidden;
}
<button id="b_undo">UnDo Button</button>
<div id="b_container"></div>

Upvotes: 1

DCR
DCR

Reputation: 15665

you need to take the document.getElementsByClassName("clicked") out of your for loop.

var arr = ["can", "san", "tan", "ban", "man", "yan", "fan", "van", "zan", "ran", "xan", "gan"];
for (let i = 0; i < arr.length; i++) {
  document.getElementById('dv').innerHTML += "<input type='button' class='button' onclick='typeItem(this.value,this.id)' value='" + arr[i] + "'>";
  document.getElementsByClassName('button')[i].id = "id" + i;
}

var typedItems = [];

function typeItem(val, idd) {
  document.getElementById(idd).style.visibility = 'hidden';
  document.getElementById(idd).classList.add('clicked');
  typedItems.push(val);
}

function undo() {
  var hidden = document.getElementsByClassName("clicked")
  for (let i = 0;i < hidden.length; i++) {    
    hidden[i].style.visibility = 'visible';
  }
  typedItems = [];
};
* {
  text-align: center
}

input,
button {
  margin: 3px;
  width: 23%;
  height: 50px;
}
<button style="background:orange" onclick="undo()">UnDo Button</button>

<br><br><br>

<p id="dv"></p>

<br>
<p id="dvv"></p>

Upvotes: 1

Barmar
Barmar

Reputation: 781058

The undo() function assumes that the elements in typedItems correspond to the elements with the clicked class.

This is true the first time that you call undo(). If you click n times, there will n elements with class="clicked" and n elements in the array,.

But it won't be true the next time. undo() empties the array, but it doesn't remove any of the clicked classes, it just makes the clicked elements visible.

So if you click 3 elements, click the undo button, and then click 3 different elements and click the undo button again, it will make the first 3 elements with the clicked class visible. But these won't necessarily be the same 3 elements you clicked the second time. document.getElementsByClassName() returns the elements in the order they appear in the DOM, not the order that you added the class.

Instead of looping over typedItems, you can loop over the elements with the class.

function undo() {
    document.querySelectorAll(".clicked").forEach(el => el.style.visibility = "visible");
}

Upvotes: 1

Related Questions