Jonas: Let's now create a nice effect
on our page navigation,
where all the links fade out when we hover
over one of them, except for the link
that we actually hovered over.
And this will teach us something really valuable,
which is how to pass arguments
into event handler functions.
And the effect that I mean is this one.
So, when we hover over one of the links,
you see, all the others fade out like this.
And that includes even the logo there on the left side.
So, let's do that here in our page,
and let's again, start by taking a look here at the HTML.
So we have these links.
So each of them is a nav_link.
And so these are the elements
that we're gonna be working with.
So, menu fade animation.
But now, of course, we do not want to attach
an event listener to each of these links.
So we already know that we should do
event delegation here instead.
So let's find the common parent element
of all of the links,
and also, including the logo there.
So if we were only working with the links,
it would be this element,
but we also want to work with the logo here.
And so let's actually use this entire navigation here
as our parent container on which we will handle the event
that is gonna bubble up from the links.
So keep in mind that all of this works
because events bubble up from their target.
So, let's select the navigation here
and store it in a variable.querySelector('.nav').
Okay.
And actually, let me put this here at the very top
because we are gonna need this a bit later.
And it is a good practice to have all of these at the top.
And the same, actually here.
So why not have all of the selections right at the top?
That makes it a bit easier to understand the whole file.
Okay?
But anyway, let's now attach
an event listener to that navigation.
But now, we're not gonna use the click event,
but instead, the mouseover event, okay?
And I think that previously, we have already used
the mouse enter event,
and mouseover is actually similar to mouseenter,
with the big difference that mouseenter
does not bubble, okay?
But here, we need the event to actually bubble
so that it can even reach the navigation element.
And so, therefore, we use mouseover, all right?
So then attach the function here
and there are also kind of opposite events
of mouseover and mouseenter.
And we use these to basically undo
what we do on the hover.
So the opposite of mouseenter is mouseleave,
and the opposite of this mouseover is mouseout.
And so we're also gonna need that one,
so let's put that here right away.
So mouseout, all right?
And as always, if you need to know more,
then you can check out the MDN documentation.
Great.
So we have our parent element,
and now as always, we need to match the element
that we are actually looking for.
And so in this case, that are these elements
with the nav_link class on them.
And so let's simply check for that.
So, if e.target, as you already know,
.classList.contains
the nav_link class.
Well, then let's do something.
So, you see that this time around,
I'm not using the closest methods.
And that's because there are simply no child elements
that we could accidentally click here
in this link, right?
So that was the reason why we needed
the closest method here in this tabs
because we had this button,
but then we could also click on the span element.
And so here we then needed to find the closest element.
So the closest button to both of these places, okay?
But here that's not necessary.
And so, therefore ,a simple check
like we have here is enough.
And so now we can actually say
that the clicked
is then e.target, okay?
So I called it clicked before,
let's call it now actually the link.
But this is similar to what we did before also.
So creating a variable which contains
the element that we're working with.
Now, right.
And so now, next up,
we need to select the sibling elements.
So basically all the other links, all right?
And remember that we can do that by going to the parent
and then selecting the children from there.
Now, in this case, actually the parent of nav_link
is this nav_item.
And the only thing that nav_item includes
is always just one link.
So you see that each of the link
is actually inside of one nav_item, like this.
And so now we would have to move up manually,
not just once, but twice.
And so instead of doing that,
we will again use the closest method, okay?
So again, instead of moving up manually,
like one or two steps, we can simply search for a parent
which matches a certain query.
And so that's a bit more robust
because even if we would, then at some point,
maybe change the structure of this HTML here,
then our JavaScript would keep working.
All right?
So let's say our link,
and then find the closest parent,
and that's actually search for nav again, okay?
Even though that's not the closest parent,
I mean, there is another parent to these links,
which is this one here.
But it's no problem of also choosing
an even higher up parent like we are doing here.
So we are now at a parent of all of the links,
and so now from there,
we can search for the nav_links again.
And so these are then going to be the siblings
of our initial links.
And so, as we already learned before,
we can use query selector on an element to search
for a certain query only in that element.
Okay?
And we are looking for these nav_links, of course.
And now, let's actually also select the logo,
and we could select it manuall also,
by its class name, but let's just suppose
that there are many navigations on this page.
And so, again, to make the solution really robust,
it's best to simply move up to the closest parent,
in this case, the navigation.,
and then from there, we simply search for an image.
All right?
And so this then will work not only on this navigation,
but it would work also on others.
So this selector here is simply for any image
which has the image tag, okay?
All right.
So, we have all our elements selected,
now we just need to change the opacity,
basically off the siblings, of the selected link.
So, siblings.forEach,
and now we actually need to do
that comparison that we did before.
So checking if the current element is not the link itself.
Because of course, this sibling here,
so these siblings, they will contain
or initial link as well.
Okay?
So it needs to be different from link.
And actually, here, we need a querySelectorAll, right?
We want all the links, not just the first occurrence.
Okay?
But then for all the others that are not the original link,
we want to change the opacity to 0.5.
And indeed, we want to do the same with the logo.
So logo.style.
And let's see what we have already.
And you see that it works, right?
Beautiful.
Now, the thing is that, of course, it doesn't go back.
So once we have it at 0.5,
it will not automatically go back to the capacity of one,
which is the original one.
You see?
So when I hover this, all the others becomes 0.5,
but as I move out,
then everything remains the same, okay?
And so that's why we have this mouseout event,
to basically undo what we did here.
So let's take all of this,
paste it here
and change this to one, all right?
And so, let's see what happens now.
And, yeah, everything goes back to one.
And so this actually works.
Now, of course, it doesn't work with the logo,
because this entire effect only works
if the target contains the nav_link class, right?
But that wasn't the point anyway.
We just wanted this to work on any of the links.
And notice that this button here
is actually also a link element.
And so it also works on that one, all right?
So our effect here is actually working already.
But this is, of course, very repetitive.
So the code here is always the same,
and so we need to make our code
a little bit more dry here, of course.
So let's refactor this code.
And usually, refactoring works by creating a new function.
And so let's do that here.
Our function, and we will need some arguments here,
but more about that later.
So, what we need to do now
is to compare these two pieces of code
that we're trying to refactor and then figure out
what is the same and what is different.
So, in this case, that's pretty simple.
So all the changes is that here, we have the opacity 0.5,
and here we have the opacity of one.
And so, we can simply take this code
and create an argument or a parameter for that opacity.
And we can then pass that opacity into the function.
All right?
So, of course, we also need the event here.
So that's gonna be the first one,
and then we need the opacity.
And so here, we simply replace that by opacity.
Okay, and select this.
We refactored our code very nicely here.
But now, how do we actually use this function here?
So usually, when we have the event handler
as a separate function,
all we do here is to pass in that function
and then it's going to work just like this, right?
So we have done this many times
throughout this course, right?
But now, the problem is that we actually want
to pass in values into this function, right?
So we need to tell this function to use
the opacity of 0.5 in this case,
and have one in this case.
Now, right?
Also, we need a way of passing this event.
So right now, none of this would work.
So let me show that to you.
So I'm not clicking, of course,
but you see, it would not really work, okay?
So, maybe you would think that we could do this.
So like, maybe passing an event here,
and then 0.5, which is the opacity that we want.
But this, of course, is not going to work.
So the first problem is that e is of course, not defined.
But the main problem really here
is that addEventListener here expects a function.
So we need to pass a function.
But if we call the function,
then all of this here will become some other value.
In this case, that's undefined,
because we don't return anything
from this function, all right?
And so this is simply not gonna work.
So we talked about this many times,
but it's always good to remember
that JavaScript indeed expects here a function,
and not just some other regular value
which would be the result of calling the function like this.
Now, the solution to this problem
would be to still have a callback function here,
like a regular one, which JavaScript will then call for us
whenever the event happens.
And then in here, we could then actually call
this function with the event, which is this one,
and then our capacity.
So, 0.5.
And so this works,
because here we are basically calling the function manually.
So this will only be executed
as soon as JavaScript executes this function value.
And so here we are back to working,
because here we are back to passing
in a real function, okay?
And then let's, right away, do the same here.
Set it to one, and now it should be working again.
And it does, indeed.
Okay, so that is the second version
of our code working, but we can actually do even better
and remove these anonymous callbacks
functions here all together.
So this looks a little bit ugly, right?
Like having just this one function
which in turn will call another function.
And so as I just said, we can do even better,
and that is by using the bind method
that we already studied before.
So, remember that the bind method
creates a copy of the function that it's called on,
and it will set the disc keyword in this function call
to whatever value that we pass into bind, okay?
So let me just do that here in practice,
so handleHover, and then .bind, okay?
And I think we actually already did an example like this.
So using bind in an event handler.
And so, let's set 0.5 here just as before.
Now, right?
And now let's do the same here.
So handleHover.bind and then one.
And so this is gonna work
because this is gonna be also a function,
because bind, remember, returns a new function.
Now in this function,
this variable will now be set to this value.
So, to one here, and to 0.5.
And so let's check that out.
So to this variable, okay?
And so now you see indeed,
that it is either one, or 0.5.
Now, right?
Now, remember that usually,
this keyword is equal to current target.
So let's also check that, okay?
But current target will, of course, remain unaltered.
So you see that it is still, of course,
the navigation element, okay.
So by default, this keyword is the same
as the current target,
so the element on which the event listener is attached to,
but when we then set this keyword manually,
of course, it becomes whatever we set it to.
So now, just like before,
we can use this keyword
and use that here, all right?
Because this keyword is now our opacity.
And so essentially, we use the bind method here
to pass an argument into a handler function.
So let me just write that here.
Passing an argument into a handler.
And I'm using quotes here, because of course,
this is not really an argument.
So in fact, we don't even need this here.
And in fact, it is impossible to pass another argument
into an eventHandler function.
So any handler function like this one
can only ever have one real argument.
And so, in this case, can only ever have one real parameter,
and that is the event.
But if we want to pass additional values
into the handler function,
then we need to use the disk keywords,
like we just did here.
And if we wanted multiple values,
then we could of course, pass in here
like an array or an object instead of just one value.
So this is kind of a workaround into the fact
that the handler function can only take one argument.
So, it's really nice effect and as I said in the beginning,
it also taught us how we can pass arguments,
essentially, into handler functions.