0

I am trying to do the following:

a) Add a class from an array containing the values one, two, three to all the divs with the class .tab-col. The first div in the class .tab-col should have the class one, second div should have class two, etc. => This is what addCol() does in code below

b) After a) is done, trying to grab the tab-col divs, and adding the class one to the first child element (col-attr), two to the second, etc. . => What addAttr() is attempting to do.

I have succeeded with a) and partially succeeded with b). The problem I am having is that only the .tab-col one's children elements are being labelled with the classes one, two, three. Whereas the other tab-cols children are not adding the classes one, two and three to their children elements.

function addCol() {
   var elements = document.querySelectorAll(".tab-col");
   var array = ["one", "two", "three", "four", "five", "six", "seven", "eight"];
   var index = 0,
     length = elements.length;
   for (; index < length; index++) {
     elements[index].classList.add(array[index]);
   }
 }

 addCol();

 function addAttr() {
   var elements = document.querySelectorAll(".tab-col");
   var array = ["one", "two", "three", "four", "five", "six", "seven", "eight"];

   var index = 0,
     length = elements.length;
   for (; index < length; index++) {
     var select = document.querySelectorAll(".tab-col" + "." + array[index] + "> .col-attr");
     for (var i = 0, length = select.length; index < length; i++) {
       select[i].classList.add(array[i]);
     }
   }
 }

 addAttr();
<div class="table">
  <div class="tab-col">
    <div class="col-attr"></div>
    <div class="col-attr"></div>
    <div class="col-attr"></div>
  </div>
  <div class="tab-col">
    <div class="col-attr"></div>
    <div class="col-attr"></div>
    <div class="col-attr"></div>
  </div>
  <div class="tab-col">
    <div class="col-attr"></div>
    <div class="col-attr"></div>
    <div class="col-attr"></div>
  </div>
</div>

Here is a JSBIN replicating the problem: http://jsbin.com/hohuxewixi/edit?html,css,js,output

(Note: Because there is no content, you will have to open up your browser's console in the output area (inspect element))

My question how can I have .tab-col two and .tab-col three to have their children elements (.col-attr) have the classes one, two and three, just as it is for .tab-col one (if you look at the completed JSBIN that will run the JavaScript)? Any help would be greatly appreciated!

15
  • What is your question? Commented Feb 3, 2017 at 23:53
  • What is classList? Commented Feb 3, 2017 at 23:53
  • 1
    Looks like you are re-using length in the inner for loop. Commented Feb 3, 2017 at 23:55
  • @Michael classList. Commented Feb 3, 2017 at 23:55
  • 1
    Should be trivial to use regular loops instead -> jsfiddle.net/che2a8km/2 Commented Feb 4, 2017 at 0:19

3 Answers 3

3

You are ovveriding the values of index and length inside the inner loop. Use different variables like this:

function addAttr(){
    var elements = document.querySelectorAll(".tab-col");
    var array = ["one", "two", "three", "four", "five", "six", "seven", "eight"];

    // the index and length that you're overriding inside the loop
    var index = 0, length = elements.length;
    for( ;index < length; index++){
        var select = document.querySelectorAll(".tab-col" + "." + array[index] + "> .col-attr");

        // you shouldn't override the values of index and length, use other variables
        var index2 = 0, length2 = select.length;
        for(; index2 < length2; index2++){
            select[index2].classList.add(array[index2]);
        }
    }
}

Test:

function addCol() {
  var elements = document.querySelectorAll(".tab-col");
  var array = ["one", "two", "three", "four", "five", "six", "seven", "eight"];
  var index = 0,
    length = elements.length;
  for (; index < length; index++) {
    elements[index].classList.add(array[index]);
  }
}

addCol();




function addAttr() {
  var elements = document.querySelectorAll(".tab-col");
  var array = ["one", "two", "three", "four", "five", "six", "seven", "eight"];

  // the index and length that you're overriding inside the loop
  var index = 0,
    length = elements.length;
  for (; index < length; index++) {
    var select = document.querySelectorAll(".tab-col" + "." + array[index] + "> .col-attr");

    // you shouldn't override the values of index and length, use other variables
    var index2 = 0,
      length2 = select.length;
    for (; index2 < length2; index2++) {
      select[index2].classList.add(array[index2]);
    }
  }
}

addAttr();
<div class="tab-col">
  <div class="col-attr">A</div>
  <div class="col-attr">B</div>
  <div class="col-attr">C</div>
</div>

<div class="tab-col">
  <div class="col-attr">D</div>
  <div class="col-attr">E</div>
  <div class="col-attr">F</div>
</div>

<div class="tab-col">
  <div class="col-attr"></div>
  <div class="col-attr"></div>
  <div class="col-attr"></div>
</div>

Sign up to request clarification or add additional context in comments.

4 Comments

Have tried copying and pasting that answer inside my addAttr function in both JSBin and in Atom. This code unfortunately does not work. Only the first child in the first .tab-col has the class one in it.
@the12 I had a little mistake i++ should be index2++. I updated my answer. It's working as you can see in the snippet. By the way, if you want the .col-attrs of a .tab-col to not have the same class, then change index to index2 where I commented // \/ this index should ....
Thanks for your effort and the knowledge that I have overridden values if you name them the same thing. However, unfortunately the code is not working as the children divs (.col-attr) is now for the first tab-col (one, one, one), and the second (two, two, two). I'd like the children divs for each of tab-col classes to have the classes one, two and three.
@the12 I updated my answer anyway! I thought you wanted it like that. Anyway, the new updated answer works as you want!
1

You may want to reconsider your approach.

CSS has a powerful construct for selecting particular child elements called nth-of-type. Here's an MDN reference about it. This nth-of-type differs from another nth-child selector only in the slightest way and it may be what your after in this and other circumstances. Here's an mdn reference on nth-child.

// querySelector and querySelectorAll in JS support css selectors
// so there is no problem using the nth child selector
var elements = document.querySelectorAll(".col-attr:nth-child(3)");

for (var i = 0; i < elements.length; ++i) {
  elements[i].style.backgroundColor = "orange";
  elements[i].style.width = "100px";
  elements[i].style.height = "20px";
}
/* We can select the first child columns of each row like so */
.col-attr:nth-child(1) {
  width: 100px;
  height: 20px;
  background-color: cornflowerblue;
}

/* We can select the second child of each row like this */
.col-attr:nth-child(2) {
  width: 100px;
  height: 20px;
  background-color: tomato;
}
<div class = "table">
  <div class="tab-col">
    <div class="col-attr"></div>
    <div class="col-attr"></div>
    <div class="col-attr"></div>
  </div>

<div class = "tab-col">
  <div class="col-attr"></div>
  <div class="col-attr"></div>
  <div class="col-attr"></div>
</div>

<div class = "tab-col">
  <div class="col-attr"></div>
  <div class="col-attr"></div>
  <div class="col-attr"></div>
</div>

You can do more advanced selections with nth child. Inside the parentheses when you add a single number like :nth-child(1) it says select that numbered nth child and that one only. When you type :nth-child(2n) it understands it as selecting every number that is even. When you type :nth-child(2n+1) it understands it as select every odd number. For any of these nth child selections to understand it you need to know that n takes on the values of the nonnegative integers ({0,1,2,3, ...}). When you type :nth-child(3n+5) the first thing you can think of it selecting is 3(0)+5th element or the 5th element then it will select the 3(1)+5th element or the 8th element and so on incrementing n each time by one until it selects all elements that are available and in the context that its selecting from. If you think of it as an+b with a and b as variables a nice way to think of this is starting from the number b select that element and every ath element after it.

1 Comment

lol funny thing is I actually knew about these selectors, but did not use them. Yeah, this is way easier than doing what I was doing. Definitely going to be playing around with this today. Thank you for this very helpful piece of advice!
0

You have

for(var i=0, length = select.length; index < length; i++){

You should use i instead of index. Just a copy and paste error by the looks of it.

for(var i=0, length = select.length; i < length; i++){

2 Comments

Changed i to index. It did not do anything to the code in question.
You need to rename length as well.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.