JavaScript JavaScript and the DOM Responding to User Interaction Listening for Events with addEventListener()

Yanitsa Stancheva
Yanitsa Stancheva
1,471 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

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
1,471 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
1,471 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>

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
1,471 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,735 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.