Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Interacting with the DOM Responding to Events Listening for Events with addEventListener()

Iterating through adding event listeners to an HTMLCollection using a for...of loop

Hi friends, quick question about adding event listeners to an HTML collection. In Reggie's lessons on adding event listeners, we create an HTMLCollection of list items using the getElementsByTagName method:

const listItems = document.getElementsByTagName('li');

Iterating through the list using a standard for loop with a counter works:

for (let i = 0; i < listItems.length; i++) {
  listItems[i].addEventListener('mouseover', () => {
    listItems[i].textContent = listItems[i].textContent.toUpperCase();                          
  });
}

However, if I try to apply the event listeners using a for...of loop, it seems to apply only to the last list item only:

for (item of listItems) {
  console.log(item.textContent);
  item.addEventListener('mouseover', () => {
     item.textContent = item.textContent.toUpperCase();
  });
}

If I go ahead and specify an event target, it will work per the first for loop:

for (item of listItems) {
  console.log(item.textContent);
  item.addEventListener('mouseover', (e) => {
     e.target.textContent = e.target.textContent.toUpperCase();
  });
}

Can any bigBrain out there help me understand why the first for...of loop would only be applying the event listener to the final item in the HTMLCollection?

2 Answers

Stephen Cole
PLUS
Stephen Cole
Courses Plus Student 15,809 Points

You're missing the let keyword in the for...of statement.

for (let item of listItems) {
  item.addEventListener('mouseover', () => {
  item.textContent = item.textContent.toUpperCase();                         
  });
};

You asked:

Can any bigBrain out there help me understand why the first for...of loop would only be applying the event listener to the final item in the HTMLCollection?

I think it's the event handler you added, e.

It runs through every loop and gets reused. Therefore, it get's the last value it sees, the last item on the list. Drop it and it will work.

I haven't tested it, but I am wondering if it is down to a syntax used in the for of loop.

So instead of:

for (item of listItems) {
...
}

I would try it again with:

for (let item of listItems) {
...
}

I imagine this is why it chooses the last one, looks like a good example to dive into deeper and understand why it is doing this exactly (something I will do as well as I don't have the exact or a good answer on this).

UPDATE: I did a quick test in the Chrome console and confirm that this is the issue, you will still log out the elements selected in the console, but still not sure exactly why it adds the event listener to the last one.