0

I want to add classes named like those in data array (categories) to each boxes in sequence (in container). For example, first box except "box" class should have: "highlighted" "special-header" "important" classes. I tried to do it like this, but it doesn't work:

var boxes = document.querySelectorAll('.box');

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

    //Add classes to all boxes
    var categories = data[i].categories;
    boxes[i].classList.add(categories)
  }

I feel that it has to be something with forEach() or with another loop refers to categories array. How to refer to each element in "categories" separately?

var data = [{
    id: 'box1',
    title: 'First box',
    content: '<p>Lorem ipsum dolor sit amet!</p>',
    categories: ['highlighted', 'special-header', 'important']
  },
  {
    id: 'box2',
    title: 'Second box',
    content: '<p>Lorem ipsum dolor sit amet!</p>',
    categories: ['special-header', 'important']
  },
  {
    id: 'box3',
    title: 'Third box',
    content: '<p>Lorem ipsum dolor sit amet!</p>',
    categories: ['highlighted', 'important']
  },
  {
    id: 'box4',
    title: 'Fourth box',
    content: '<p>Lorem ipsum dolor sit amet!</p>',
    categories: ['highlighted']
  },
  {
    id: 'box5',
    title: 'Fifth box',
    content: '<p>Lorem ipsum dolor sit amet!</p>',
    categories: []
  },
];
var boxes = document.querySelectorAll('.box');

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

  //Add classes to all boxes
  var categories = data[i].categories;
  boxes[i].classList.add(categories)
}
<div class="container">
  <div class="box">
    <header></header>
    <p></p>
  </div>
  <div class="box">
    <header></header>
    <p></p>
  </div>
  <div class="box">
    <header></header>
    <p></p>
  </div>
  <div class="box">
    <header></header>
    <p></p>
  </div>
  <div class="box">
    <header></header>
    <p></p>
  </div>
</div>

1
  • I made you a snippet. See the error? You need to fix that to make a minimal reproducible example - test if categories is empty Commented Nov 14, 2018 at 13:26

3 Answers 3

2

From the classList documentation:

add or remove multiple classes using spread syntax

var boxes = document.querySelectorAll('.box');

for (var i = 0; i < boxes.length; i++) {
  var categories = data[i].categories;
  boxes[i].classList.add(...categories)
}

But here's the thing. If you've got all that data, why aren't you using it to build the HTML, rather than fill in the gaps? Here's an example:

var data = [{"id":"box1","title":"First box","content":"<p>Lorem ipsum dolor sit amet!</p>","categories":["highlighted","special-header","important"]},{"id":"box2","title":"Second box","content":"<p>Lorem ipsum dolor sit amet!</p>","categories":["special-header","important"]},{"id":"box3","title":"Third box","content":"<p>Lorem ipsum dolor sit amet!</p>","categories":["highlighted","important"]},{"id":"box4","title":"Fourth box","content":"<p>Lorem ipsum dolor sit amet!</p>","categories":["highlighted"]},{"id":"box5","title":"Fifth box","content":"<p>Lorem ipsum dolor sit amet!</p>","categories":[]}];

// `map` over the data and return an array of HTML strings
const boxes = data.map(({ id, title, content, categories }) => {
  return `
    <div class="box ${categories.join(' ')}" id="${id}">
      <header>${title}</header>
      ${content}
    </div>
  `
});

// join the array and add the HTML to the container
const container = document.querySelector('.container');
container.insertAdjacentHTML('beforeend', boxes.join(''));
.box { border: 1px solid black; }
.special-header { color: green; }
.important { border: solid 1px red; }
.highlighted p { background-color: yellow; }
<div class="container"></div>

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

3 Comments

Liking the map...
Just to add a bit, you could create a document fragment, then create the elements and add them to the document fragment then add the fragment to the container. It's quicker than parsing the html string, but for such a small data set I like your code better, nice and clean.
That was an excercise to do it with arrays, objects and loops. I am too newbie to do it in that way ;)
1

You need to massage the array a little and test for empty

Here I use the ...spread syntax to allow adding an array using .add

var data = [{ id: 'box1', title: 'First box', content: '<p>Lorem ipsum dolor sit amet!</p>', categories: ['highlighted', 'special-header', 'important'] }, { id: 'box2', title: 'Second box', content: '<p>Lorem ipsum dolor sit amet!</p>', categories: ['special-header', 'important'] }, { id: 'box3', title: 'Third box', content: '<p>Lorem ipsum dolor sit amet!</p>', categories: ['highlighted', 'important'] }, { id: 'box4', title: 'Fourth box', content: '<p>Lorem ipsum dolor sit amet!</p>', categories: ['highlighted'] }, { id: 'box5', title: 'Fifth box', content: '<p>Lorem ipsum dolor sit amet!</p>', categories: [] }, ]; 

var boxes = document.querySelectorAll('.box');

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

  //Add classes to all boxes
  var categories = data[i].categories;
  boxes[i].querySelector("header").innerHTML=data[i].title || ""
  boxes[i].querySelector("p").innerHTML=data[i].content.replace(/<\/?p>/,"");
  if(categories.length>0) boxes[i].classList.add(...categories)
}
.highlighted { background-color:yellow; }
 .specialheader { font-weight:bold; }
 .important { font-style :italic; }
<div class="container">
  <div class="box">
    <header>Header 1</header>
    <p>Para 1</p>
  </div>
  <div class="box">
    <header>Header 2</header>
    <p>Para 2</p>
  </div>
  <div class="box">
    <header>Header 3</header>
    <p>para 3</p>
  </div>
  <div class="box">
    <header>header 4</header>
    <p>Para 4</p>
  </div>
  <div class="box">
    <header>Header 5</header>
    <p>para 5</p>
  </div>
</div>

Comments

0

Check the length of the categories array in your data before adding the class, if the array is empty it throws an error, check the fix below. (added the spread operator:

var boxes = document.querySelectorAll('.box');

for (var i = 0; i < boxes.length; i++) {
    let box = boxes[i];

    //Add classes to all boxes
    var categories = data[i].categories;
    if (categories.length) box.classList.add(...categories); // check category length
}

If you were going old school and wanted to avoid the spread operator or newer JS syntax:

var boxes = document.querySelectorAll('.box');

for (var i = 0; i < boxes.length; i++) {
    let box = boxes[i];

    //Add classes to all boxes
    var categories = data[i].categories;
    if (categories.length) {
       categories.forEach(function(cl) { box.classList.add(cl); });
    }
}

3 Comments

Not enough. You need to handle the array too
That is ok. It throws an error but classes are added, despite the error. It is about how to add (it adds whole string to box, like: highlighted,special-header,important). And because of it classes doesn't work. There should not be any comma and should be spaces between.
The above code should work, the spread operator does the trick, if you are looking fro a more old school approach that doesn't use the newer JS syntax you could iterate with a forEach and anonymous function, see code above. @mplungjan - Thanks and good catch.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.