Day 17: Events
Lesson 2: onmouseover and onmouseout
Target vs currentTarget
CSS have the :hover
pseudo class that allows us to change styling when we hover the mouse over an element. What if we want to do more than that though. What if we want to change some data. Let's add a due day to our todo and show it when we hover.
To do that we will use two events, the onmouseover
event to show the due day and the onmouseout
to hide it again.
First of all we need to learn about target
and currentTarget
, add this line to your todos.forEach()
function on the line above listItem.append(content)
.
1listItem.onmouseover = (e) => { 2 console.log(e.target.innerText); 3};
Now hover over Bake cake in your list and look at the console. You will see Bake cakeDone
because that is all the text inside the element you have hovered on, even though the button is a child element it's text appears here as well.
Now hover on a Done button. You will see Done
in the console. Does this make sense?
Let's think about this. We added an event to the <li>
so when we hover on it we see all it's innerText. That makes sense because the .target
is the thing we hovered on.
But when we hover on the <button>
we still get the event but now we only see the Done
text. This is is because the .target
and how events bubble up through the DOM.
We hovered on the button, which is the target
because our cursor is on it. It doesn't have an onmouseover
event handler, but it does bubble the event up to it's parent element, the <li>
, which does have an onmouseover
event handler, so this gets triggered and we see the log. But we don't see it's full text, just the Done
... because the target
is still just the <button>
that caused the event to fire.
So, what if we want to get a reference to the <li>
even when we hover on the child <button>
, we can use currentTarget
which is a reference to the element that has the event handle and not the element that caused the event in the first place.
Change e.target.innerText
to e.currentTarget.innerText
, hover on the button and see that we now go back to logging Bake cakeDone
😁
So this is actually really important to get. The element that causes the event to fire, isn't always the same as the thing that actually has the event handler attached to it.
If you ever need to check "is the thing that fired this event (target
) the same as the thing that is calling the event handler (currentTarget
)" then you can do this check in your event handler:
1element.onmouseover = (e) => { 2 if (e.target !== e.currentTarget) { 3 return; 4 } 5 // code you want to run 6};
onmouseover and onmouseout
So, how do we show this due day, let's get to it.
Change your todos array to this:
1const todos = [ 2 { description: "Walk dog", important: true, due: "today" }, 3 { description: "Watch TV", important: false, due: "today" }, 4 { description: "Bake cake", important: false, due: "tomorrow" }, 5];
and now add this inside your listItem.onmouseover
function
1const due = document.createElement("p"); 2due.textContent = todoItem.due; 3listItem.appendChild(due);
This will create a paragraph tag and show it below the item. Hover on an item and see what happens.
It works but the due day stays on the screen and then more and more add as you hover around. So now we need remove them!
After your onmouseover
function and before listItem.appendChild(content);
add this function:
1listItem.onmouseout = (e) => { 2 const p = listItem.getElementsByTagName("p"); 3 listItem.removeChild(p[0]); 4};
This gets all the child paragraphs in the <li>
and then removes the first one (there will only be one as onmouseover
will only fire one when your cursor enters the <li>
so we can just remove the first, and only, child paragraph)
Go hover now, much better.
Not the greatest UI to look at but for this course that doesn't matter too much, we are just focussing on the functionality of JavaScript and not the styling of HTML and CSS. If you want to make this experience really nice and are good with HTML and CSS then you have all the tools you need to make something really nice looking - go have fun 😊