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 JavaScript and the DOM (Retiring) Responding to User Interaction Listening for Events with addEventListener()

Yanitsa Stancheva
Yanitsa Stancheva
2,979 Points

error with loop

Hi everyone,

I keep getting the following error from the console:

Uncaught TypeError: Cannot read property 'textContent' of undefined at HTMLLIElement.listItems.(anonymous function).addEventListener

I don't know where the problem is :( this is my code:

const toggleList = document.getElementById('toggleList'); const listDiv = document.querySelector('.list'); const descriptionInput = document.querySelector('input.description'); const descriptionP = document.querySelector('p.description'); const descriptionButton = document.querySelector('button.description'); const addItemInput = document.querySelector('input.addItemInput'); const addItemButton = document.querySelector('button.addItemButton'); const listItems = document.getElementsByTagName('li')

for(var i = 0; i<listItems.length; i+=1){ listItems[i].addEventListener('mouseenter', ()=>{ listItems[i].textContent = listItems[i].textContent.toUpperCase() }) listItems[i].addEventListener('mouseout',()=>{ listItems[i].textContent = listItems[i].textContent.toLowerCase() }) }

Ashley Carpenter
Ashley Carpenter
13,393 Points

I just wanted to add markup to your code. It will make it easier:

const toggleList = document.getElementById('toggleList'); 
const listDiv = document.querySelector('.list'); 
const descriptionInput = document.querySelector('input.description'); 
const descriptionP = document.querySelector('p.description'); 
const descriptionButton = document.querySelector('button.description'); 
const addItemInput = document.querySelector('input.addItemInput'); 
const addItemButton = document.querySelector('button.addItemButton'); 
const listItems = document.getElementsByTagName('li')

for(var i = 0; i<listItems.length; i+=1)
{ listItems[i].addEventListener('mouseenter', ()=>{
 listItems[i].textContent = listItems[i].textContent.toUpperCase() 
}) 
listItems[i].addEventListener('mouseout',()=>
{ listItems[i].textContent = listItems[i].textContent.toLowerCase() 
}) 
}

4 Answers

Hi Yanitsa,

I found two solutions for your problem.

Solution 1

This has a simple fix, change var i = 0 to let i = 0 in your for loop. That's it!

Solution 2

for(var i = 0; i<listItems.length; i+=1)
{ 
    const anItem = listItems[i];

    anItem.addEventListener('mouseenter', ()=>{
        anItem.textContent = anItem.textContent.toUpperCase();
    });

    anItem.addEventListener('mouseout', () => {
        anItem.textContent = anItem.textContent.toLowerCase();
    });
}

Explanation

So the reason that var acts all weird has to do with its scope or visibility.

Difference between var and let:

for(let i = 0; i < 100; i++){
    //i is not visible outside of this block
    //for each iteration of the loop there is a new i variable, in other words every iteration has its own  variable of i at that iteration
}
for(var i = 0; i < 100; i++){
    //i IS visible outside of this block
    //for each iteration of the loop there is NOT a different value for i
}

So because when we use var, each iteration of the loop does not have its own value of i, the value which your addEventListener function eventually get is 4 (because your list had three elements so at the end of the loop i would have been incremented to 4). So because of this you get the undefined error, listItems[4] is not defined since there are only li elements up to the index 3.

Conclusion

Avoid var use let.

Yanitsa Stancheva
Yanitsa Stancheva
2,979 Points

it worked! maybe I wasn't following the teacher and used var instead as I am normally used to :/ thank you very much :)))

ywang04
ywang04
6,762 Points

Just a quick question regarding difference between var and let. I am not sure why i can be printed out as different value in each iteration of the loop while you said "there is NOT a different value for i"? Thanks a lot.

for (var i=0;i<5;i++) {

  console.log(i);

}

The printed result is 0,1,2,3,4.

Ashley Carpenter
Ashley Carpenter
13,393 Points

Hi Yanitsa,

I think it might just be a couple of things - you're missing some semi colons. You need one after const listItems = document.getElementsByTagName('li') And listItems[i].textContent = listItems[i].textContent.toUpperCase() And also listItems[i].textContent = listItems[i].textContent.toLowerCase()

Like so...

const toggleList = document.getElementById('toggleList'); 
const listDiv = document.querySelector('.list'); 
const descriptionInput = document.querySelector('input.description'); 
const descriptionP = document.querySelector('p.description'); 
const descriptionButton = document.querySelector('button.description'); 
const addItemInput = document.querySelector('input.addItemInput'); 
const addItemButton = document.querySelector('button.addItemButton'); 
const listItems = document.getElementsByTagName('li');

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

    listItems[i].addEventListener('mouseout', () => {
        listItems[i].textContent = listItems[i].textContent.toLowerCase();
    });
}
Yanitsa Stancheva
Yanitsa Stancheva
2,979 Points

Hi Ashley and thank you for your reply, unfortunately it's not the semicolons :( I don't understand what am I doing wrong here

Ashley Carpenter
Ashley Carpenter
13,393 Points

Please can you show your HTML too? That will make it much easier to diagnose.

Yanitsa Stancheva
Yanitsa Stancheva
2,979 Points

<!DOCTYPE html> <html> <head> <title>JavaScript and the DOM</title> <link rel="stylesheet" href="css/style.css"> </head> <body> <h1 id="myHeading">JavaScript and the DOM</h1> <p>Making a web page interactive</p>

<button id="toggleList">Change list description</button>    
<div class ="list">
  <p class="description">Things that are purple:</p>
        <input type = "text" class="addItemInput">
<button class="description">add item</button>
  <ul>
    <li>grapes</li>
    <li>amethyst</li>
    <li>lavender</li>
    <li>plums</li>
  </ul>
      <input type = "text" class="addItemInput">
<button class="addItemButton">add item</button>
  </div>

<script src="app.js"></script>

</body> </html>