0

I'm trying to change the classname if certain links in my navigation, but the doesn't seem to want to iterate through the last item. The commented out hardcoded section works just fine

HTML

<ul id="nav-list">
    <li class="not-current"><a href="home.html">Home</a></li>
    <li class="current"><a 
    href="documentation.html">Documentation</a></li>
    <li class="not-current"><a href="designs.html">Designs and 
    Wireframes</a></li>
    <li id="last-nav-item" class="not-current"><a 
    href="meeting.html">Book a Meeting</a></li>
</ul>

JavaScript

var notCurrentLinks = document.getElementsByClassName('not- 
current');

function openMobileMenu() {
    for (let i = 0; i < (notCurrentLinks.length); i++) {
        console.log('Worked ' + (i + 1) + ' time(s)');
        notCurrentLinks[i].className = 'm-not-current';
    }            
//Hardcoding below seems to work
//notCurrentLinks[0].className = 'm-not-current';
//notCurrentLinks[1].className = 'm-not-current';
//notCurrentLinks[2].className = 'm-not-current';
notCurrentLinks = document.getElementsByClassName('m-not- 
current');
}

The console returns

  • Worked 1 time(s)
  • Worked 2 time(s)
  • 3
    Please may you share a [mcve]? Mainly you're missing the corresponding HTML – evolutionxbox Jan 10 '22 at 09:35
  • What are the classes of the items that you're selecting? In your code it looks like it is `m-not-current`, but then your for loop is updating the className to be `m-not-current` again? Or are you trying to remove additional classes? – Nick Parsons Jan 10 '22 at 09:39
  • 1
    How do you populate `notCurrentLinks`. If you use `getElementsByClassName` this is a *live* collection, ie elements may be removed from that collection when you are updating element classes. – derpirscher Jan 10 '22 at 09:40

1 Answers1

0

It's a live collection, meaning if you loop it and you change its collected items in the loop the loop will skip nodes here and there.

// example
document.body.innerHTML = '<p class="p">p</p><p class="p">p</p>';

const p = document.getElementsByClassName('p');

p.length; // 2

p[0].className = '';

p.length; // 1

Live collections are synchronous and reflecting the current state of the collection. If you don't want this to happen you need static collection instead:

// all o with class `p`
const p = document.querySelectorAll('.p');

Now even if p[0].className = '' happens, that collection will still have that previously .p element in it.

Andrea Giammarchi
  • 3,038
  • 15
  • 25