Looping With DOM Elements

Open the project folder

In our starter files, open the index.html page from this lessons folder:

04.Events-And-The-DOM > 08.Looping-with-dom-elements

Looping uses

When even creating a small number of elements using JavaScript things can get repetitive. Imaging creating a list with even five or ten items. We create the list item elements, then the content, then adding to a parent would be a lot of lines of code.

Or, if we wanted to add the same class to lots of elements, again it is a lot of work and repetition. To help with this we can use loops. Although we do have more on loops in a later section, we have already looked at some examples of looping in the arrays section. We used map and forEach to run a function for each item in the array.

This was a way of reducing repetition and this can also be applied to anything such as our DOM elements.

In the starter file, we can work with the header list items since there is more than one:

<ul class="nav-inline">
  <li class="nav-item">our burgers</li>
  <li class="nav-item">history</li>
</ul>

We can use loops to get all these list items, and make a change, such as adding a class, or removing them all.

First, grab all the list items with querySelectorAll:

// ========= LOOPING =========
const listItems = document.querySelectorAll('li');

To add the classes manually, we would need to do something like this:

// ========= LOOPING =========
const listItems = document.querySelectorAll('li');
listItems[0].classList.add('inline');

Here we need to select each list item by the index number (listItems[0]). If we had lots of elements to do this for, it would get repetitive, so instead we can use a loop.

The for of loop

JavaScript has lots of types of loops available, but a relatively simple one we can use for this case is called for of:

// ========= LOOPING =========
const listItems = document.querySelectorAll('li');
for (const item of listItems) {
  // this loop will repeat for each item in listItems, which is twice:
  item.classList.add('inline');
}

We can use const here because the value of item never changes, it only selects one element at a time then moves onto the next one. This loops through our listItems, and on each loop the current value is stored into the item variable.

We can do anything to these selected elements, even remove them if we want:

for (const item of listItems) {
  item.classList.add('inline');
  item.remove();
}

The forEach loop

An alternative approach is to make use of a built-in method called forEach (comment out for of section).

Over to the console where we can see this. Type in listItems in the console and expand the contents:

NodeList(2) [li.nav-item.inline, li.nav-item.inline]
0: li.nav-item.inline
1: li.nav-item.inline
length: 2
[[Prototype]]: NodeList

Expand the Prototype which will reveal the forEach method:

[[Prototype]]: NodeList
entries: ƒ entries()
forEach: ƒ forEach()
item: ƒ item()
keys: ƒ keys()
length: (...)
values: ƒ values()
constructor: ƒ NodeList()
Symbol(Symbol.iterator): ƒ values()
Symbol(Symbol.toStringTag): "NodeList"
get length: ƒ length()
[[Prototype]]: Object

Remember from an earlier lesson that we get back a NodeList from querySelectorAll(). Inside the Prototype, it inherits various properties and methods we can use, one of them is forEach:

const listItems = document.querySelectorAll('li');
listItems.forEach(function (item) {
  item.classList.add('inline');
});

Re-creating our example with JavaScript

This is how we can modify, but what about creating new elements, such as these full list items? Let’s try this out using the same methods vwe seen previously. Before we create new ones, comment out the old ones in the HTML:

<ul class="nav-inline">
  <!-- <li class="nav-item">our burgers</li> -->
  <!-- <li class="nav-item">history</li> -->
</ul>

First, comment out the previous examples and we can create a regular list item:

const listElement = document.createElement('li');
const listText = document.createTextNode('our burgers');
listElement.appendChild(listText);
listElement.classList.add('nav-item');
document.querySelector('ul').appendChild(listElement);

This will display one single list item in the browser. As we know, we would need to repeat these five lines to create item number two and so on.

Using the same for of loop we can repeat this. We need the names of the list items (text content), which we can add to an array:

// 1. create links
const links = ['our burgers', 'history'];
// 2. then for of loop
for (const link of links) {

}

This loop will run twice, once for each item in our array. But what do we want to run? Well, we want to run the 5 lines of code from above (cut/paste contents into the loop body):

const links = ['our burgers', 'history'];

for (const link of links) {
  const listElement = document.createElement('li');
  const listText = document.createTextNode(link);
  listElement.appendChild(listText);
  listElement.classList.add('nav-item');
  document.querySelector('ul').appendChild(listElement);
}

This will now display our two links in the browser header area. We have not saved a huge amount of code, but the benefits would be bigger if we had more than two list items to create.

Using forEach with arrays

Alternatively, arrays also have a forEach method, so we could use this too if we wanted:

links.forEach(function (link) {
  // same 5 lines as inside for of loop:
  const listElement = document.createElement('li');
  const listText = document.createTextNode(link);
  listElement.appendChild(listText);
  listElement.classList.add('nav-item');
  document.querySelector('ul').appendChild(listElement);
});

Loops are a great way to perform repetitive tasks in programming, and we will look at some more types of loops later.