I am actually trying to add class (Selected) to the li when clicked and remove Class from neighbour li.
Issue is it doesn't work when there is 2 ul, the below code only work on the 1st ul or when i click on the li of the second li, first li active gets removed
const menuLis = document.querySelectorAll("#top-nav > li");
for (let li of menuLis) {
li.addEventListener("click", function(){
// 1. Remove Class from All Lis
for (let li of menuLis) {
li.classList.remove('selected');
}
// 2. Add Class to Relevant Li
this.classList.add('selected');
});
}
.selected{color:red}
<ul id='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<ul id='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Thank you for the help
CodePudding user response:
You need to use a class, as well to separate handling for each ul for it to properly work:
const menuUls = document.querySelectorAll('.top-nav');
for (const ul of menuUls) {
const menuLis = ul.querySelectorAll('li');
for (const li of menuLis) {
li.addEventListener('click', function () {
// 1. Remove Class from All Lis
for (let li of menuLis) {
li.classList.remove('selected');
}
// 2. Add Class to Relevant Li
this.classList.add('selected');
});
}
}
.selected{color:red}
<ul class='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<ul class='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
You can select the element's siblings
, and remove the selected
class.
const menuLis = document.querySelectorAll(".top-nav > li");
for (let li of menuLis) {
li.addEventListener("click", function(){
for (let sibling of this.parentNode.children) {
sibling.classList.remove('selected');
}
this.classList.add('selected');
});
}
.selected{color:red}
<ul class='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<ul class='top-nav'>
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
CodePudding user response:
Ids must be unique - one per page only, so you should use a class instead.
Another thing to think about is: on every click you're adding new listeners to all the list items which might be okay for a small example but might prove inefficient at scale.
An alternative method would be to use event delegation - attach one listener to each parent element, the list item, and check the information on the event target to update its list items.
const menus = document.querySelectorAll('.top-nav');
menus.forEach(menu => {
menu.addEventListener('click', handleClick, false);
});
function handleClick(e) {
const { nodeName, parentNode } = e.target;
// If the clicked element is a list item
if (nodeName === 'LI') {
// Find all the list items of the current list
const items = parentNode.querySelectorAll('li')
// Remove the class from each, and then add the
// class to the element that was clicked
items.forEach(i => i.classList.remove('selected'));
e.target.classList.add('selected');
}
}
.selected { color:red; }
li:hover { cursor: pointer; }
<ul class="top-nav">
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<ul class="top-nav">
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>
Additional documentation