I\'m performing a small text with JavaScript with the getElementsByClassName()
and I am getting some unwanted results. I would like the script to change each CS
First, the below code should do the trick in the simplest way.
var blockSet = document.getElementsByClassName("block-default").className = "block-selected";
Next what goes wrong with your code, or rather what is the interesting thing that is happening:
blockSet[0].className = 'block-selected';
makes the first block set element no longer a block set element. That leaves you with 7 remaining. Now,
blockSet[1].className = 'block-selected';
Selects the second one of the remaining ones. Which would be the third one of your complete list. Now you have 6 remaining.
blockSet[2].className = 'block-selected';
This makes the third one among the remaining, which would be your BLOCK5 into a block selected. And results in you having 5 remaining.
blockSet[3].className = 'block-selected';
This again finds your fourth one which is BLOCK7 when you count to the fourth among your remaining. And now you have 4 remaining.
blockSet[4] onwards find no such element and fail to execute. This is what happens with your code. Quite interesting. :).
Here is a jsfiddle alerting you the values as they run: https://jsfiddle.net/xz7h57jv/
document.getElementsByClassName returns a HTMLCollection object, which is live
An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.
So when you call
blockSet[0].className = "block-selected";
You changed the underlying document and that item is not in the collection anymore (the blockSet[0] is now the second item in your original selection).
Because you change the .className
of the blockSet
which is an HTMLCollection. The collection that have elements with same class (block-default
) will change when the elements suffers some updates.
In other words when you change the .className
of an element the collection will exclude that element. This means that the size of the HTMLCollection
will decrease . Also the size will increase if an element with that class has beed added to the DOM.
To solve this you can always change only the first element .className
.
for(var i = 0; i<blockSetLength; i++)
{
blockSet[0].className = "block-selected";
}
Notes: Intead of changing class element by element, you can iterate through elements with for
and change .className
.
var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;
console.log(blockSet);
for(var i = 0; i<blockSetLength; i++)
{
blockSet[0].className = "block-selected";
}
.block-default {
width: 100px;
height:50px;
background-color: green;
border: 1px solid red;
padding:10px;
}
.block-selected {
width: 100px;
height:50px;
background-color: blue;
border: 1px solid white;
padding:10px;
}
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>
If you add a new item in DOM (not collection) the size will increase as presented in the example below.
var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;
alert("Current size: " + blockSet.length);
document.body.innerHTML += '<div class="block-default">BLOCK9</div>';
alert("After adding an element in DOM size: " + blockSet.length);
.block-default {
width: 100px;
height:50px;
background-color: green;
border: 1px solid red;
padding:10px;
}
.block-selected {
width: 100px;
height:50px;
background-color: blue;
border: 1px solid white;
padding:10px;
}
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>
function change() {
var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;
for (var i = 0; i < blockSetLength; i++) {
blockSet[0].className = "block-selected";
}
}
.block-default {
width: 100px;
height: 50px;
background-color: green;
border: 1px solid red;
padding: 10px;
}
.block-selected {
width: 100px;
height: 50px;
background-color: blue;
border: 1px solid white;
padding: 10px;
}
<button onclick="change()">change</button>
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>
what you were doing wrong is every time you change the class the colllection re-evaluates and decreases in size.
Your error occur because .className return a live HTMLCollection. So when you do something like this:
blockSet[0].className = "block-selected";
Your collection blockSet[0]
will become the blockSet[1]
. So when you execute the line :
blockSet[1].className = "block-selected";
You not change the blockSet[1]
you think but you change the starting blockSet[2]
.
So you can do this:
var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;
for(var i=0;i<blockSetLength;i++){
blockSet[0].classList.add('block-selected'); //add the new class first
blockSet[0].classList.remove('block-default'); //delete the old one
}
http://jsfiddle.net/94dqffa7/
I think it's the best way to do it. Because the classList.add()
and classList.remove()
will help you to change your class without eleminate the others class you have on your div (if you have some). Also, you need to add the new one before remove the old one or you will have the same problem as before.
You can find the working code over here
<div class="block-default">BLOCK1</div>
<div class="block-default">BLOCK2</div>
<div class="block-default">BLOCK3</div>
<div class="block-default">BLOCK4</div>
<div class="block-default">BLOCK5</div>
<div class="block-default">BLOCK6</div>
<div class="block-default">BLOCK7</div>
<div class="block-default">BLOCK8</div>
var blockSet = document.getElementsByClassName("block-default");
var blockSetLength = blockSet.length;
for (i = 0; i < blockSetLength; i++) {
blockSet[0].className = "block-selected";
}
Demo link http://jsfiddle.net/patelmit69/9koxfaLq/1/