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()

boi
boi
14,242 Points

Can't sleep

My code for all the three questions is the same

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Interacting with the DOM</title>
        <link href="css/style.css" rel="stylesheet" />
    </head>
    <body>
        <div class="wrapper">
            <header>
                <h1 id="headline">My Day</h1>
                <div class="group">
                    <label for="main">Your task</label>
                    <input type="text" id="main" class="input-main" />
                    <button id="btn-main">Add Task</button>
                </div>
            </header>

            <button class="btn-toggle">Hide List</button>

            <div class="list-container">
                <ul>
                    <li class="item">Learn JavaScript</li>
                    <li class="item">Walk the cat</li>
                    <li class="item">Bake cookies</li>
                    <li class="item">Write a blog post</li>
                </ul>
                <button class="btn-remove">Remove Last Task</button>
            </div>
        </div>

<!--        <script src="app.js"></script>-->
        <script src="temp.js"></script>
    </body>
</html>
const listItems = window.document.getElementsByTagName('li');
const listItemsNode = window.document.querySelectorAll('.list-container li');

const inputValue = window.document.getElementById('main');
const button = window.document.getElementById('btn-main');
const unorderedList = window.document.querySelector('.list-container ul');

button.addEventListener('click', () => {
  if (inputValue.value) {
    unorderedList.insertAdjacentHTML('afterbegin', `<li>${inputValue.value}</li>`);
    console.log(inputValue.value);
    inputValue.value = '';
    const listboi = window.document.querySelector('.list-container ul li');
    listboi.className = 'item';
  } 
});


for ( let i = 0; i < listItems.length; i++) {
  console.log(i)
  console.log(listItems[i]);
  listItems[i].addEventListener('mouseover', (event) => {
     listItems[i].textContent = listItems[i].textContent.toUpperCase();
//     console.log(event.target);

👇 //Just trying out both loops to see results
for ( let listItem of listItems ) {
  console.log(listItem);
//  listItem.addEventListener('mouseover', () => {
//     listItem.textContent = listItem.textContent.toUpperCase();
//  });
};

  });
};

Question 1

When a new list item is added to the ul upon the mouseover on the second item it triggers the newly added item to capitalize with the toUpperCase() method. Why does it trigger when I hover my mouse on the second or third item? I can't seem to understand the connection.

Question 2

When using the console.log(listItems[i]) Sometimes I see a different type of value in the console when I refresh. (Same code as above pasted)

The Console Should be expecting 👇

<li class="item">Learn JavaScript</li>
<li class="item">Walk the Cat</li>
<li class="item">Bake cookies</li>
<li class="item">Write a blog post</li>

But sometimes see this upon refreshing the page👇

li.item
li.item
<li class="item">Bake cookies</li>
<li class="item">Write a blog post</li>

or

li.item
li.item
li.item
<li class="item">Write a blog post</li>

or

li.item
li.item
li.item
li.item

What is going on here? something to do with the load speed?

Question 3

While running the for loop I noticed that the loop runs once upon loading the page. Adding more items using the button element seems to not trigger the for loop again, judging by the console.log method inside the for loop. How does everything stay dynamic while the for loop is static?

Console

0
1
2
3   

When I add a new list item using the function the console does NOT print out the for loop value again. When everything is run once how does the browser behavior stay dynamic?

1 Answer

Steven Parker
Steven Parker
231,172 Points
  1. There's currently no code to convert the text back into lower case, so when you hover the second item, the first isn't triggered but just remains in upper case.
  2. I was not able to replicate this behavior. A better way to share code is to make a snapshot of your workspace and post the link to it. This allows an exact duplicate of your environment to be used for analysis (and saves posting a lot of code).
  3. The "for" loop is in the global scope so it runs as part of the page loading. But when the button is pushed, only the code inside the callback function that was given to the addEventListener runs, and that loop is not part of that function.
boi
boi
14,242 Points

Hey, Steven! Glad to see you, it's been a while. :)

  1. Try adding an item with the "Add Task" button and hover on the second item "Walk the Cat". It will trigger the newly added item to UpperCase. Why does it behave like that?

  2. I've added a snapshot and provided some image links of my console.

My console shows all li.item

My console shows combined types upon refreshing

My console now works as expected upon refreshing several times

Snap in the SHOT

Steven Parker
Steven Parker
231,172 Points

In the mouseover handler code, i is not a local variable, so listItems[i] gets resolved before the code runs using the loop value. This works OK until an item is added, at which point all the indexes are off by 1. So when each item is triggered, it changes the one above it. The function should use traversal from event.target to identify the element:

     listItems[i].textContent = listItems[i].textContent.toUpperCase();    // instead of this
     event.target.textContent = event.target.textContent.toUpperCase();    // do THIS

Then, whenever you assign textContent, it replaces the entire element. So, updating a list item that includes any child elements (such as the paragraph and a heading will replace them with a single text node.

The "li.item" is a browser shorthand, it should have a triangle after it you can click to expand and show all the attributes. It sounds like the one you want to see is outerHTML:

  console.log(listItems[i]);            // so instead of this...
  console.log(listItems[i].outerHTML);  // do THIS
boi
boi
14,242 Points

Thanks for the explanation. The last issue I have is with question 2. I understand the logic of your explanation, my issue is why the browser behaves differently with the same code after refreshing it. It's not like I change something. I believe it has to do something with load speed.

Like I showed, sometimes after refreshing the browser 👇

li.item
li.item
<li class="item">Bake cookies</li>
<li class="item">Write a blog post</li>

or

li.item
li.item
li.item
<li class="item">Write a blog post</li>

or

li.item
li.item
li.item
li.item

Strange. Anyways, I've understood the concepts but just have an issue with the browser behavior.

Steven Parker
Steven Parker
231,172 Points

That one I don't know. But I'd guess that the setting of some other attribute affects the default display.
At least you know how to guarantee consistent output now.