4

I am trying to loop through 2 arrays. The first array is the link name the second array is the links 'a' value. I want to loop through the two arrays attaching the value of the second array to the href of each link that is created / in the first array. This is what I have and it not working for me.

const links = ['Home', 'Contact', 'About'];
const hrefLinks = ['/', 'contact', 'about'];

for (let i = 0; i < links.length; i++) {
    for (let j = 0; j < hrefLinks.length; i++) {
        if (links.length === hrefLinks.length) {
            const li = document.createElement('li');
            const liLink = document.createElement('a');
            liLink.setAttribute('href', hrefLinks[i]);
            liLink.className = 'Test-Class';
            li.appendChild(liLink);
            li.className = 'nav-link';
            list.appendChild(li);
            li.innerHTML += links[i];
        }
    }
}

I do have it working with one forEach loop but got confused on how I would nest the second forEach;

const links = ['Home', 'Contact', 'About'];
const hrefLinks = ['/', 'contact', 'about'];

 links.forEach(function (link) {
     const li = document.createElement('li');
     const liLink = document.createElement('a');
     li.appendChild(liLink);
     li.className = 'nav-link';
     list.appendChild(li);
     li.innerHTML += link;
 });

Is this the proper way of doing this or is there an easier / cleaner way of doing this?

Perry Craft
  • 309
  • 3
  • 15

4 Answers4

5

You don't want a nested loop - you simply need to link the ith item in links to the ith item of hrefLinks. With forEach, you can do this just by using the second argument to the callback, which will refer to the current index being iterated over:

const list = document.body.appendChild(document.createElement('ul'));


const links = ['Home', 'Contact', 'About'];
const hrefLinks = ['/', 'contact', 'about'];

links.forEach((linkName, i) => {
  const li = document.createElement('li');
  const a = document.createElement('a');
  a.href = hrefLinks[i];
  a.textContent = linkName;
  li.appendChild(a);
  li.className = 'nav-link';
  list.appendChild(li);
});
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • _"You don't want a nested loop"_ - Please elaborate on this. Performance wise, `for` loops are much faster than `forEach` loops. So I'd like to know _why_ it should be avoided? – icecub Dec 11 '18 at 06:15
  • @icecub There's no need for each `links` item to be used in conjunction with each `hrefLinks` item (`O(N^2)`), so a nested loop doesn't make sense. A nested loop (whether `for` or `forEach`) wouldn't accomplish anything useful. While `for` loops are faster than `forEach` and other array methods, the array methods make for far cleaner code: more functional, automatic abstraction, no need for manual iteration, no hoisting problems (in case the code is in ES5), etc – CertainPerformance Dec 11 '18 at 06:19
  • @icecub A nested loop would be useful if each item had to do something with each item in the other array, eg here, if one wanted `['Home-/', 'Home-contact', 'Home-about', 'Contact-/', 'Contact-contact', ...]` – CertainPerformance Dec 11 '18 at 06:20
  • Thanks for the explanation. I didn't see the bigger picture there so ye, now it makes sense :) – icecub Dec 11 '18 at 06:22
  • @icecub it was most likely my poor explanation. I am very noob on all of this still so I don't quite know exactly how to explain things properly – Perry Craft Dec 11 '18 at 06:29
2

create an objects array which holds the link name and url, then you can iterate that object for add the anchor elements into you dom, as follows

//an object which hold navigation url and name
var navLinks = [{
  label: 'Home',
  href: '/'
}, {
  label: 'Contact',
  href: 'contact'
}, {
  label: 'About',
  href: 'about'
}]

navLinks.forEach(function(link) {

  var li = document.createElement('li');
  li.className = 'nav-link';

  var liLink = document.createElement('a');
  var linkText = document.createTextNode(link.label);
  liLink.appendChild(linkText);
  liLink.className = 'Test-Class';
  liLink.href = link.href;

  li.appendChild(liLink);
  document.body.appendChild(li)

});
Azad
  • 5,144
  • 4
  • 28
  • 56
1

Replace for-loops by this (we update document only once):

document.body.innerHTML += links.map( (link,i)=>`
    <li class="nav-link">
        <a class="Test-Class" href="${hrefLinks[i]}">${link}</a>
    </li> 
`).join('');

const links = ['Home', 'Contact', 'About'];
const hrefLinks = ['/', 'contact', 'about'];

document.body.innerHTML += links.map( (link,i) =>  `
    <li class="nav-link">
        <a class="Test-Class" href="${hrefLinks[i]}">${link}</a>
    </li> 
`).join('');

editable example here. If you need better performance use insertAdjacentHTML. I don't change input data but better approach is when you put href and link in single object like in azad answer, and then use map.

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
0

why don't you use an array of objects except for two arrays?

const anchors = [
  {
    name: 'Home',
    link: '/'
  },
  {
    name: 'Contact',
    link: 'contact'
  },
  {
    name: 'About',
    link: 'about'
  }
];

let ul = document.getElementById('list');

anchors.forEach(function(item) {
  let li = document.createElement('li');
  let a = document.createElement('a');
  a.className = 'nav-link';
  a.href = item.link;
  a.innerHTML = item.name;
  li.appendChild(a);
  ul.appendChild(li);
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Anchors</title>
</head>
<body>
  <ul id="list"></ul>
</body>
</html>

I think this is efficient.

Sajeeb Ahamed
  • 6,070
  • 2
  • 21
  • 30