1

I have the following html for 3 dropdown checklists (The anchor span is clicked to make the unnumbered list visible)

for (var checkList of document.querySelectorAll('.dropdown-check-list')) { 
   checkList.getElementsByClassName('anchor')[0].onclick = function(evt) {
   if (checkList.classList.contains('visible'))
      checkList.classList.remove('visible');
   else
      checkList.classList.add('visible');
   }
}
.dropdown-check-list {
  display: inline-block;
}
.dropdown-check-list .anchor {
  margin-top: 6px;
  width: 357px;
  position: relative;
  cursor: pointer;
  display: inline-block;
  padding: 5px 50px 5px 10px;
  border: 1px solid #ccc;
}   
.dropdown-check-list ul.items {
  padding: 2px;
  display: none;
  margin: 0;
  border: 1px solid #ccc;
  border-top: none;
}
.dropdown-check-list.visible .items {
  display: block;
}
<div id="list1" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Expired Metadata<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list2" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Groups<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list3" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Teams<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

However, when I click any of the anchor spans it only opens the last list (div.list3). The spans do not correspond to the correct list. Is there any way to fix this?

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
Raj Patel
  • 15
  • 2
  • 2
    Note that [`classList.toggle('visible')`](https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle) does the same thing as the whole `if/else` block you have. – Heretic Monkey Apr 22 '21 at 19:19

3 Answers3

1

checkList is a var which does not stay the same after the first iteration, yet, you're expecting to be a local constant variable that's used in another scope (wrapped in a function, executed on clicks).

You have to change the variable to either be of type let, as such, scoped in the local spectrum, or make another variable within the iteration to keep it in the memory.

for (let checkList of document.querySelectorAll('.dropdown-check-list')) { 
   checkList.getElementsByClassName('anchor')[0].onclick = function(evt) {
   if (checkList.classList.contains('visible'))
      checkList.classList.remove('visible');
   else
      checkList.classList.add('visible');
   }
}
.dropdown-check-list {
  display: inline-block;
}
.dropdown-check-list .anchor {
  margin-top: 6px;
  width: 357px;
  position: relative;
  cursor: pointer;
  display: inline-block;
  padding: 5px 50px 5px 10px;
  border: 1px solid #ccc;
}   
.dropdown-check-list ul.items {
  padding: 2px;
  display: none;
  margin: 0;
  border: 1px solid #ccc;
  border-top: none;
}
.dropdown-check-list.visible .items {
  display: block;
}
<div id="list1" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Expired Metadata<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list2" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Groups<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list3" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Teams<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>
Nora
  • 612
  • 3
  • 11
  • Appendum, see [What's the difference between using “let” and “var”?](https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var) – Nora Apr 22 '21 at 19:08
0

First of All: Function declared in a loop contains unsafe references to 'checkList' variables... you can read more about it here: Function declared contains unsafe references

Second of All: when you define a variable with var keyword, it does not stay the same after the first iteration... should use let

Third of All: or you can use this snippet for JS part and it does not have those issues:

document.querySelectorAll('.dropdown-check-list').forEach(item => {
    item.addEventListener('click', event => {
       if (item.classList.contains('visible')){
      item.classList.remove('visible');
       }
   else{
     item.classList.add('visible');
   }
  }
)
})
reza khademi
  • 430
  • 4
  • 11
-1

try this snippet bellow.

document.querySelectorAll('.dropdown-check-list').forEach(el => el.addEventListener('click', evt => {
  evt.currentTarget.classList.toggle('visible');
}))
.dropdown-check-list {
  display: inline-block;
}

.dropdown-check-list .anchor {
  margin-top: 6px;
  width: 357px;
  position: relative;
  cursor: pointer;
  display: inline-block;
  padding: 5px 50px 5px 10px;
  border: 1px solid #ccc;
}

.dropdown-check-list ul.items {
  padding: 2px;
  display: none;
  margin: 0;
  border: 1px solid #ccc;
  border-top: none;
}

.dropdown-check-list.visible .items {
  display: block;
}
<div id="list1" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Expired Metadata<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list2" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Groups<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>

<div id="list3" class="dropdown-check-list" tabindex="100">
  <span class="anchor">Unregistered Teams<span class="count">20</span></span>
  <ul class="items"> ... </ul>
</div>
Waseem Almoliky
  • 771
  • 6
  • 10