تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Event Bubbling Basics0:57

I'm selecting each element using querySelector, and then I'm adding an event listener for clicks and just alerting the tag name, so section, div, and P. So let me just save that. And even if you don't know what event bubbling is, if you just think about it, I think it makes logical sense. So if I click on the P element, of course we're clicking on the element, but since it's nested, we're also clicking on the div, which is its parent, and we're also clicking on the section. So it makes sense to emit those events as well if there are event listeners on them. So if that's your logic, then if we click P here, you'll see that all of those event

Target vs CurrentTarget3:00

So P div and section. Actually, let me change that back to click. So we'll change this back to click. And now we should get P div and section. And we do. But it's also console.log event.target and event.currentTarget. So we can see the difference. So let's say console.log event.target is, and I'll put event.target as the second param. Because if I put it as a string, it will just print out a string representation and we want the actual object to show.

Because if I put it as a string, it will just print out a string representation and we want the actual object to show. So we'll say event.target. And it's the same for currentTarget. So let's say event.currentTarget is event.currentTarget. Okay, change this to currentTarget. Okay. And let's paste this into the other ones as well. And this one down here. Okay, save.

And this one down here. Okay, save. And let's click P and let's see what we get. Let me just scroll up here. Now, if you look at eventTarget, it's always the same no matter where we are in the bubbling phase. And you saw I clicked on the P element. So eventTarget is P here. It's also P when we get to the div. It's also P when we get to the section. However, currentTarget changes based on where you are in the bubbling path.

Stopping Event Propagation4:37

Now, event bubbling can be pretty useful. That's why it works the way it does by default. But sometimes you might not want the events to bubble. So for example, when we click on P here, we only want that event to run. And we don't want any event handlers on the parents to run. So if that's the case, then you can make use of event.stopPropagation. So for example, if we added that on the P element, so down here, we can say event.stopPropagation as a method. And now when I click on P, or the P element, the event handler for that should run, but the parents should not run.

And now when I click on P, or the P element, the event handler for that should run, but the parents should not run. So let me save this. Let's click on the P. And you can see only the P is run. Let me just clear this. Since we didn't stop propagation or bubbling on the div, that should still work the same way it did before. So we should get div and section. And we do.

Event Capturing Phase5:25

So we should get div and section. And we do. Now event capturing is similar to bubbling, but in the opposite direction. So instead of starting from the target element, for example, if we clicked on the P, you saw that it worked its way upwards. So P to div to section. With capturing, you start at the parent element and move your way downwards towards the target element. So in this case, if I click the P, it's going to start at the section,

and move your way downwards towards the target element. So in this case, if I click the P, it's going to start at the section, go to the div, and then go to the target that we clicked. So this is not as common as a use case as bubbling, but the option is there. So to do that, actually, let me just remove this propagation or stopPropagation. So that should work the same way it did. So if I click on P, we should get P, div, and section. And we do.

So if I click on P, we should get P, div, and section. And we do. But if you want to use capturing instead of bubbling, then you can set the third param to true when you call addEventListener. I believe you can set it as an object of options as well, but just setting it to true as a Boolean should work too. So let's do that case. So the third param is after this callback. So we'll set it for all three. Let's say , true.

So we'll set it for all three. Let's say comma, true. So let's go ahead and save that. And now if I click on the P tag, you should see that it will go from top down. So if I click on the P here, we start at the section, we go to the div, and then we go to the P tag, which was the element that was actually clicked.

Event Delegation with To-Dos7:03

I'll just paste in some markup. And it's just this unordered list of to-dos like we've been working on. So if I save that, there it is in the browser. And within the list items, we have a delete button to delete the to-do. So here, here, and here. So if we wanted to add functionality to this delete button, we can add an event listener for each one of these buttons. And I showed you how to do that in the previous chapter.

And for this to-do app specifically, when we add a to-do, we'll use JavaScript to add a new list item here. And if you forget to add an event listener for the delete button in that case, then delete won't work for that specific item. With event delegation, the idea is to move the event listener to a nearby parent, so in this case, the unordered list, instead of the button here,

if you have a bunch of to-dos. So I'll just do it right here. So let's say document.querySelectorAll. And we're grabbing the delete to-dos as a class. And there should be a noteList. We can foreach over all of them using foreach. And for each iteration of the loop, I spelled foreach wrong, we should get a deleteButton. This is an arrow function or a callback.

we should get a delete button. This is an arrow function or a callback. And then we can add an event listener as we've been doing. So deleteButton.addEventListener, click, and we'll just say function and spell that wrong. And we'll just console.log deleteToDo. Again, this will work fine. So if I save this, click on delete, these should work, and they do.

So if I save this, click on delete, these should work, and they do. So again, it's adding an event listener for each one of these buttons here. So if we had 100 to-dos, then we'll have 100 event listeners. So with event delegation, like I said, the idea is to move the event listener on a parent and then have that parent delegate down to its children. So let's get rid of this, or comment it out at least.

and then have that parent delegate down to its children. So let's get rid of this, or comment it out at least. And let's select our unordered list. Let's say const toDoList equals document.querySelector. And let's just select the UL here since it's the only one on the page. So now let's add an eventListener on that toDoList. So toDoList.addEventListener, click is fine. And let's just do the same thing. So function event, and let's just console.log UL was clicked.

And like I showed you earlier, we can use event.target to get the element that was actually clicked on. So let's go ahead and console.log event.target. And let's see what we get. So depending on where we click, we'll either get one of the elements within the UL. So let's see. In this case, we got the span. If I click here, we get the actual UL. If I click on the button, we should get the button.

If I click here, we get the actual ul. If I click on the button, we should get the button. And I believe if I just click somewhere in between the button and the span, we should get the list item. And we do. Now, we're only interested in clicks for the button. So if we just add a conditional within here, we can only listen for clicks on that button. So let's just say if event.target,

we can only listen for clicks on that button. So let's just say if event.target, and there are a few ways to do this. I'll just grab the classList, and we'll just check for the deleteToDo class. contains, deleteToDo. deleteToDo. So if that's the case, then that means we're clicking on the button. So let's just console.log button was clicked.

then that means we're clicking on the button. So let's just console.log button was clicked. So console.log button was clicked. And now, if I save that, this code will only run when the delete button is clicked. So if I click here, nothing will happen. Here, nothing, nothing, nothing, until I actually hit the delete button. And now it reacts. Again, nothing here, nothing here,

Handling Nested Click Targets11:46

and add an element, or a nested element. So let's just select that. How about we make a strong tag? So now we have a nested strong within the button. Let's save that. Now we're clicking on the strong tag. So if I hit delete, you'll see it's not working. And if I bring back the console.log here, you'll see we are clicking the strong tag. Okay.

And we only want to react to clicks when we click on either the strong tag or the button tag. So what we can do is search up the tree. So the method for that is the closest method and just search for the button. So quick fix here. We can say event.target.closest. So the closest element that has the matching selector. So in this case, I'll just match the delete-to-do class, which is the button.

So in this case, I'll just match the delete to do class, which is the button. And now this should somewhat work. So let's get rid of this console.log here and let's see if this works. So let me save that. Now let's click on the delete button and it does work. However, if I click the actual span, we get an error here. So when we're clicking on the span, it's looking up the tree for an element.

So when we're clicking on the span, it's looking up the tree for an element that matches this selector here. It can't find it. So it's null. And then we run classList on null. So that's why we get this error. So quick fix here. Let's just save this to a variable. Let's name it deleteButton.

Let's just save this to a variable. Let's name it deleteButton. Let's define that variable here. const deleteButton equals that. And if it can't find the deleteButton, so we can say if not deleteButton. So this just means that it's not found. Then we can just stop executing the code. So we can say return. But if it does, then this code will not be run.

So we can say return. But if it does, then this code will not be run. And then the delete button will be found in this code here. So if I save this, this should work now. Delete works. And even if we click the span, that should not result in an error this time. So yeah, that's event delegation along with bubbling and capturing. And you'll definitely be making use of these.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟