1

I have simply an unordered list am trying to create with html5 and javascript, I want to add events to this list element eg first element.

Here is my HTML list:

<ul class="aside__list">
    <li class="one">Kutomba kuma</li>
    <li class="two">Kutomba tako</li>
    <li class="three">Kutomba mkundu</li>
    <li class="four">Kutomba malaya</li>
</ul>

JS:

var parentElements = document.getElementsByClassName('aside__list');
for (var i=0; i<parentElements.length; i++) {        
    parentElements[i].addEventListener('click', doStuff, false);
    console.log(parentElements[i]);
}

function doStuff() {
    alert('Delete me');
}
   

I want to add an event to the first element of my list using for loop without using a class or id, now this event applies to every list element in my list,

what do I need to change to get what I want?

Anurag Srivastava
  • 14,077
  • 4
  • 33
  • 43
The Dead Man
  • 6,258
  • 28
  • 111
  • 193
  • Your code makes a classic performance mistake, not only by using `.getElementsByClassName()`, but by referencing the live node list returned by it inside of a loop. See **[this](https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474)** for an explanation. – Scott Marcus Mar 02 '19 at 23:43

3 Answers3

4

You can use:

document.querySelector('ul.aside__list li').addEventListener('click', doStuff);

This matches the first li so you don't need to include :first-child.

Anurag Srivastava
  • 14,077
  • 4
  • 33
  • 43
2

Add a listener to the li which is the first child of the list, instead of to every whole .aside__list:

document.querySelector('.aside__list li:first-child').addEventListener('click', doStuff);

function doStuff() {
  console.log('Delete me');
}
<ul class="aside__list">
  <li class="one">Kutomba kuma</li>
  <li class="two">Kutomba tako</li>
  <li class="three">Kutomba mkundu</li>
  <li class="four">Kutomba malaya</li>
</ul>

As comment notes, the :first-child psuedo-selector isn't necessary since querySelector will only return the first matching element, though it may make the code's intent a bit clearer.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 2
    Semi-related, `:first-child` shouldn't be necessary, as `querySelector` only matches a single element anyways. – jhpratt Mar 02 '19 at 23:28
2

This would work for any number of ul.aside__list:

[...document.querySelectorAll('.aside__list')].forEach(
  ul => ul.firstElementChild.addEventListener('click', doStuff)
);

function doStuff() {
  console.log('Delete me');
}
<ul class="aside__list">
  <li class="one">Kutomba kuma</li>
  <li class="two">Kutomba tako</li>
  <li class="three">Kutomba mkundu</li>
  <li class="four">Kutomba malaya</li>
</ul>
<ul class="aside__list">
  <li class="one">Kutomba kuma</li>
  <li class="two">Kutomba tako</li>
  <li class="three">Kutomba mkundu</li>
  <li class="four">Kutomba malaya</li>
</ul>
<ul class="aside__list">
  <li class="one">Kutomba kuma</li>
  <li class="two">Kutomba tako</li>
  <li class="three">Kutomba mkundu</li>
  <li class="four">Kutomba malaya</li>
</ul>
connexo
  • 53,704
  • 14
  • 91
  • 128
  • Why not just `querySelectorAll('.aside__list li')`? The end result is the same, and it avoids fetching the entire list. – jhpratt Mar 02 '19 at 23:32
  • @jhpratt Because that would select all list items inside each list. – connexo Mar 02 '19 at 23:32
  • Whoops, tack a `:first-child` on the end of that then. – jhpratt Mar 02 '19 at 23:33
  • Can you explain why did you choose to use `foreach` and not `for loop` as question suggest? – The Dead Man Mar 02 '19 at 23:35
  • Because it's more readable, does not require an index variable and lets you access the iterated elements without using the clunky `element[i]` syntax. – connexo Mar 02 '19 at 23:58
  • @jhpratt `document.querySelectorAll('.aside__list li:first-child').length === document.querySelectorAll('.aside__list').length`. – connexo Mar 03 '19 at 00:01