Create a drop-down multi-level menu.
The problem is that the function does not work on those elements that come after an element that does not satisfy the if condition.
The code above is a simplified analogue of the functional: by clicking it is necessary to color what is clicked, provided that there is one more element next to it. Question: how to make the function work with all elements that have a "neighbor".

 window.onload = function(e) { var sublist = document.querySelectorAll('.dropdown-list li a'); for (var i=0; i<sublist.length; i++) { if (sublist[i].nextSibling.length !== null) { sublist[i].onclick = function(event) { // event.preventDefault(); this.style.background = 'red'; } } } } 
 <div class="dropdown-list"> <li><a href="#">111</a><span>000</span></li> <li><a href="#">222</a><span>000</span></li> <li><a href="#">333</a><span>000</span></li> <li><a href="#">444</a></li> <li><a href="#">555</a><span>000</span></li> <li><a href="#">666</a></li> <li><a href="#">777</a><span>000</span></li> </div> 

  • sublist[i].nextSibling returns the next ancestor, and this is the DOM object of the model, it does not have the .length property .length it is always undefined or the Cannot read property 'length' of null(…) error Cannot read property 'length' of null(…) if there is no ancestor at all - Vasily Barbashev
  • @ Vasily Barbashev hmm. By span, I mean the second level of the menu. I thought this way: if this second level of the menu is, then you need to expand it. if not, then do nothing. and I .nextSibling.length !== null checking if there’s something else next to the elements via .nextSibling.length !== null . How then is it better to implement a submenu display? - lexxl
  • why not choose not by a , but by li - .dropdown-list li , then you can find out how many children there will be in li with the help of childElementCount . And you will know that 1 is only a link, and 2 is a link and a span , your second level. That is if I understand you correctly) - Vasily Barbashev
  • @ Vasily Barbashev yes, that is necessary, apparently) while the flight is normal. ATP - lexxl

2 answers 2

Solved the problem as follows:

 window.onload = function(e) { var sublist = document.querySelectorAll('.dropdown-list li'); for (var i = 0; i < sublist.length; i++) { if (sublist[i].childElementCount === 2) { sublist[i].onclick = function(event) { // event.preventDefault(); this.querySelector('span').style.background = 'red'; } } } } 
 <div class="dropdown-list"> <li><a href="#">111</a><span>000</span></li> <li><a href="#">222</a><span>000</span></li> <li><a href="#">333</a><span>000</span></li> <li><a href="#">444</a></li> <li><a href="#">555</a><span>000</span></li> <li><a href="#">666</a></li> <li><a href="#">777</a><span>000</span></li> </div> 

Because .nextSibling does not have the .nextSibling property, changed the code, making a check, not through the item being searched for, on the existence of a neighboring element on the parent, but on the existence of several (in my case two) children on the parent using .childElementCount .

    You can select all spans adjacent to the links, and then take the previous element in the loop - it will be the link.

    Learn more about adjacent selectors .

    For example:

     window.onload = function(e) { var sublist = document.querySelectorAll('.dropdown-list li a + span'); [].forEach.call(sublist, function(span) { var a = span.previousElementSibling; a.onclick = function(event) { // event.preventDefault(); this.style.background = 'red'; }; }); } 
     <div class="dropdown-list"> <li><a href="#">111</a><span>000</span> </li> <li><a href="#">222</a><span>000</span> </li> <li><a href="#">333</a><span>000</span> </li> <li><a href="#">444</a> </li> <li><a href="#">555</a><span>000</span> </li> <li><a href="#">666</a> </li> <li><a href="#">777</a><span>000</span> </li> </div>