In this lesson, we will look at what it means to cancel an event, why you might want to cancel an event, and how you can cancel an event.
Instructor: [0:00] If an event is cancellable, then it can be cancelled by event listeners. Cancelling an event is a way to opt out of the default behavior associated with an event.
[0:09] I'm going to come over to my event target so I'm going to add some event listeners. In this event listener, I'm going to cancel the event using prevent default. I'll speak more about prevent default soon, but for now all you need to know is that we are cancelling the event.
[0:24] If I come up here and I dispatch the event, we'll see that even though this event listener did in fact cancel the event, the event continued to flow through the event path and all of the subsequent event listeners were still executed.
[0:39] In my example application, I'm going to add a hyperlink to my DOM events.dev visualizer. When I click on the hyperlink, it will navigate to that visualizer.
[0:52] Events have an internal cancelled flag. When an event is created, the internal cancelled flag is set to false. If an event is cancelled, then the internal cancelled flag is set to true. The clearest way to cancel an event is using the event.preventDefault method.
[1:11] Here, I'm using the querySelector API to get access to our anchor element, and then adding a click eventListener to the anchor, which is going to execute this onClick function, which we'll call, event.preventDefault. When I come over to my app and I click the hyperlink, you'll see that I'm no longer navigating to that DOM Events.div url.
[1:33] This call to event.preventDefault has cancelled the click event. The default action of navigating to the href on the anchor tag was prevented. The internal cancelled flag of an event is exposed through the defaultPrevented property.
[1:49] Here, I'm logging the event.defaultPrevented property, calling event.preventDefault, and then logging the property again. When I click on the anchor, I'll originally see that the event is not cancelled.
[2:01] After I call event.preventDefault, the event is cancelled. Event.preventDefault and event.defaultPrevented have an easily understood relationship based on their names.
[2:13] Another way to cancel an event is using the discouraged legacy behavior of setting the event.returnValue property to false. If I come over here, I click on the link, again, we will see that the event was originally not cancelled and then event.returnValue is set to false and then the event was cancelled.
[2:31] You can also read the event.returnValue property to know if an event has been cancelled. If I come over here and click on the anchor, I'll say originally for the click event, the defaultPrevented property was set to false and returnValue was set to true.
[2:45] After the cancelling of the event by using event.preventDefault, the defaultPrevented property was set to true so the event has been cancelled, and the returnValue property has been set to false.
[2:57] The returnValue property is the inverse of the defaultPrevented property, so it'll be set to true when an event has not been cancelled, and it'll be set to false when an event has been cancelled. The name returnValue is misleading because this property does not intrinsically reflect what value you return from your event listeners.
[3:17] In this case, returning false from this onclick function that is used in this event listener has no bearing on the event.returnValue property.
[3:27] I recommend always using preventDefault to cancel an event, and using the defaultPrevented property to understand if an event has been cancelled rather than leveraging setting the returnValue to false to cancel an event and reading the returnValue to know if an event was cancelled.
[3:44] Generally speaking, you can ignore these properties and just use these two. If you return false from an event listener created with addEventListener, then this return false does absolutely nothing. If I come over here and click on the anchor, I will see that the event wasn't cancelled, and I navigated through to DOM Events.div.
[4:06] Interestingly, returning false from an element property event handler does cancel an event. When I click on the link, the default behavior I'm navigating is being prevented.
[4:18] If you return false from an HTML attribute event handler, then the event will also be cancelled. When I click on the link again, the navigation is being prevented. I'm now going to change my onClick HTML attribute event handler so that it's going to call a global function called, my onClick.
[4:38] If I come back to my JavaScript file, I'll create that my onClick function on the global scope that is the window object. Here, I'm going to return false. When I click on the anchor, I'll see that the navigation wasn't prevented even though the my onClick function was returning false.
[4:56] If I come back to my HTML, I'll see that the onClick attribute was only calling this function. It wasn't actually returning the value that this my onClick function returned. My onClick is returning false, but then that false value is not being returned by this attribute.
[5:15] In order to get this to work, I have to return the value that my my onClick function returns. Now when I click on the anchor, I'll see that the navigation is being prevented.
[5:27] Return false does cancel an event but only for HTML attribute and object property event handlers. I think it's confusing to lean on the return false behavior to cancel an event especially considering that it only works for some of the event binding mechanisms.
[5:43] Your code will be much more understandable if you simply lean on event.preventDefault to cancel events. Event.preventDefault also works for all of the different EventListener binding mechanisms.
[5:55] Regardless of what mechanism you were using to cancel an event, when the internal cancelled flag of an event is set to true, then that event will always continue to be cancelled. You can't uncancel an event.
[6:08] Calling event.preventDefault for an event that is not cancelable doesn't do anything. Here I'm adding a MouseDown EventListener to the anchor and providing in my on MouseDown function which is going to log out whether the event was cancelable.
[6:24] Then going to try and cancel the event, and then it's going to log out whether the event was cancelled. Here I'm creating a new MouseDown event that is cancelable and I'm dispatching that event against the anchor element.
[6:36] You can see over here that the event was cancelable and my attempt to cancel the event was successful and the event was cancelled.
[6:45] If I change cancelable to false and I come over here, I can see that the event is not cancelable and my attempt to cancel the event was not successful and the event is still not cancelled.
[6:55] To know if an event is cancelable from within an EventListener, you can read the event.cancelable property. However, often you want to know if a particular event is able to be cancelled ahead of time.
[7:05] In order to know ahead of time if a particular event is cancelable, you can refer to the MDN event reference page. Here, I'm going to again search for the MouseDown event. I'll come in here and I can see that, yes, the event is cancelable.
[7:19] Often the main reason we want to cancel an event is to opt out of the default behavior associated with that event. Now the MDN page doesn't have any information about that. If you scroll down to the bottom under the specifications heading you'll see the relevant spec for the event you're looking at. In here MouseDown is covered under the UI event specs.
[7:38] Going to here and I can see that, yes, this event is cancelable, and under here I can see the default action. In this case the default action of MouseDown varies. It can start drag-drop operation. It can start as text selection and start a scroll pan interaction.
[7:55] If I call event.preventDefault on the MouseDown, I'm going to opt-out of these behaviors. We read that one of the default behaviors for the MouseDown event is to start a drag-and-drop operation.
[8:07] If I come over here and drag on my anchor, I'll see that a little ghost preview is created, where it says the text of the link and then the link beneath it. I can drag that over here and I can create a new tab with that link.
[8:21] Now, my own MouseDown function if I call event.preventDefault and I come back over here to my anchor and I try and drag it, you'll see that I'm no longer seeing any ghost preview of the link because I've opted out of that default behavior.