Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

className only changing every other class

Tags:

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 CSS class to a new class. The issue is that every other class is only changing...

I would like to use pure js how this issue as it is for practice purposes.

The first thing that came to mind was white spaces, although when removing the this did not make any differnce.

Can anyone point our what I am doing wrong?

<html>     <head>        <link rel="stylesheet" type="text/css" href="default.css">     </head>     <body>         <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>         <script>      var blockSet = document.getElementsByClassName("block-default");     var blockSetLength = blockSet.length;      blockSet[0].className = "block-selected";     blockSet[1].className = "block-selected";     blockSet[2].className = "block-selected";     blockSet[3].className = "block-selected";     blockSet[4].className = "block-selected";     blockSet[5].className = "block-selected";     blockSet[6].className = "block-selected";     blockSet[7].className = "block-selected";             </script>     </body> </html> 

CSS Classes:

.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;  } 
like image 780
EvilGenius82 Avatar asked Apr 12 '15 09:04

EvilGenius82


People also ask

What is getElementsByClassName () used for?

The getElementsByClassName method of Document interface returns an array-like object of all child elements which have all of the given class name(s). When called on the document object, the complete document is searched, including the root node.

Can a div have multiple Classnames?

Absolutely, divs can have more than one class and with some Bootstrap components you'll often need to have multiple classes for them to function as you want them to. Applying multiple classes of course is possible outside of bootstrap as well.

Is className the same as class?

But nothing has changed with it, the semantic meaning of both className and class is the same, when JSX is rendered, the className attribute is automatically rendered as a class attribute.


2 Answers

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>
like image 106
adricadar Avatar answered Sep 27 '22 16:09

adricadar


Instead of using getElementsByClassName(),
which returns a live HTMLCollection that will change as the classNames change,
you can use querySelectorAll(),
which returns a non-live NodeList that will not change.

querySelectorAll() has better IE support than getElementsByClassName() (IE8+ vs. IE9+).
It's also much more flexible since it supports CSS selectors (CSS2 for IE8+ and CSS3 for IE9+).

However, querySelectorAll() is slower than getElementsByClassName().
Keep that in mind if you're processing thousands of DOM elements.

Snippet

var blockSet = document.querySelectorAll(".block-default");  var blockSetLength = blockSet.length;    blockSet[0].className = "block-selected";  blockSet[1].className = "block-selected";  blockSet[2].className = "block-selected";  blockSet[3].className = "block-selected";  blockSet[4].className = "block-selected";  blockSet[5].className = "block-selected";  blockSet[6].className = "block-selected";  blockSet[7].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>
like image 41
Rick Hitchcock Avatar answered Sep 27 '22 16:09

Rick Hitchcock