Introduction to pop-up events. Advanced working with the Event object in JavaScript Canceling event bubbling js

In this lesson, we will become familiar with the concept of event bubbling, and also look at how it can be interrupted. In addition, we will find out what other stages (phases) the event goes through before it starts to emerge.

Event Bubble

If an event occurs for some element, it begins to “pop up”, i.e. occurs in a parent, then in a grandparent, etc.

It follows that an event generated by some element can be intercepted using a handler on its parent, grandparent, etc.

We will demonstrate the emergence of an event (bubble) using the following example:

Heading

Some very important text

Chapter

Some text

Rest of text

Let's write a small script with which we will add a "click" event handler for all page elements, as well as for the document and window objects.

document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i< allElements.length; i++) { allElements[i].addEventListener("click",function() {console.log(this.tagName);},false); }; document.addEventListener("click",function() {console.log(this);},false); window.addEventListener("click",function() {console.log(this);},false); });

Let's create an HTML page and paste the above HTML code into it. Script written in JavaScript, insert before the closing body tag. After this, open the newly created page in a web browser, press the F12 key and go to the console. Now let's left-click in the area belonging to the strong element and see how the event pops up.

How to interrupt event bubbling

The rising of an event (bubble) can be interrupted. In this case, this event will not be triggered for higher (parent) elements. The method that is designed to stop an event (bubble) from propagating is called stopPropagation() .

For example, let's change our example above so that the event does not bubble up above the body: document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i

Undoubtedly, surfacing is very convenient and architecturally transparent. Don't stop it unless absolutely necessary.

Getting the element that called the handler

In order to get the DOM element (object) that called the event handler, you must use the key the word this. Given keyword(this) is only available in the handler if you subscribe to the event using JavaScript.

For example, let's display in the console the id of the element that called the event handler:

Var myP = document.getElementById("myP"); myP.addEventListener("click",function())( //get the DOM element that called the event handler - this //get its id and output it to the console console.log(this.id); ));

You can also use the currentTarget property (event.currentTarget) to get the current element.

Stages (phases) of the event

Before an event begins to emerge (the ascent stage), it first goes through 2 more stages:

  • Stage 1 is the stage of immersion to the element that generated the event. Those. at this stage there is a movement from top to bottom, i.e. from window object to element. This stage is also called the interception stage.
  • Stage 2 is the stage of achieving the goal, i.e. element (object) that generated the event.

Taking into account all the stages that an event goes through, the following picture emerges:

Let's modify the above example script as follows:

Document.addEventListener("DOMContentLoaded", function() ( var allElements = document.getElementsByTagName("*"); for (var i=0; i

The third parameter of the addEventListener and removeEventListener methods determines the stage at which the event will be caught. If this parameter is set to true , the event will be intercepted at the event immersion (interception) stage. And if the parameter is false , then the event will be intercepted at the bubbling stage. To handle the event on the target itself, you can use the addEventListener method as with value false, and with the value true .

Attention: during the immersion (interception) stage, events can only be intercepted by handlers added using the addEventListener() method. Handlers added using other methods ( HTML attribute or via JavaScript using the on[event] property) can intercept events only at the bubbling stage.

Getting the element that generated the event

In order to get the target element, i.e. the element that generated the event must use the target property (event.target).

Consider the example above, in which we change the content of the script element to the following:

Document.addEventListener("DOMContentLoaded", function() ( var elementBody = document.body; elementBody.addEventListener("click",function())( console.log(this.tagName + " - the element that called the handler"); console .log(event.currentTarget.tagName + " - the element that called the handler"); console.log(event.target.tagName + " - the element that generated the event"); ),false); ));

Let's demonstrate our example by left-clicking in the area belonging to the strong element:

It all started with the use of JavaScript and classes.

However, I have a problem. I wanted to use something called Bubble Events, but I also wanted to minimize the dependencies that I would have to inject. I didn't want to connect jQuery libraries for "this little test", just to use pop-up events.

Let's take a closer look at what toasting events are, how they work, and a few ways to implement them.

Okay, so what's the problem? Let's look at a simple example:

Let's say we have a list of buttons. Every time I click on one of them it should become "active". After pressing again, the button should return to its original state.

Let's start with the HTML:

  • Pencil
  • Pen
  • eraser

I could use a standard JavaScript event handler like this:

For(var i = 0; i< buttons.length; i++) { var button = buttons[i]; button.addEventListener("click", function() { if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); }); }
Looks good... But it won't work. By at least, not the way we expect it.

Closures win For those who know a little functional JavaScript, the problem is obvious.

For the rest, I’ll briefly explain - the handler function is locked to the button variable. However, this is a single variable, and is overwritten every iteration.

In the first iteration, the variable refers to the first button. In the next one - to the second, and so on. But, when the user clicks on the button, the loop has already ended and the button variable refers to the last button, which always calls the event handler for it. Disorder.

What we need is a separate context for each function:

Var buttons = document.querySelectorAll(".toolbar button"); var createToolbarButtonHandler = function(button) ( return function() ( if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active"); ); ); for(var i = 0; i< buttons.length; i++) { buttons[i].addEventListener("click", createToolBarButtonHandler(buttons[i])); }
Much better! And most importantly, it works correctly. We have created a function createToolbarButtonHandle that returns an event handler. Then we attach our own handler for each button.

So what's the problem? It looks good and works. Despite this, we can still make our code better.

First, we create too many handlers. For each button inside the .toolbar, we create a function and bind it as an event handler. For three buttons, memory usage is negligible.

But if we have something like this:

  • Foo
  • Bar
  • // ...another 997 elements...
  • baz

then the computer, of course, will not explode from overflow. However, our memory usage is far from ideal. We allocate a huge amount of it, although we can do without it. Let's rewrite our code again so that we can use the same function multiple times.

Instead of referring to the button variable to keep track of which button we clicked, we can use an event object, which is passed as the first argument to each event handler.

The Event object contains some data about the event. In our case, we are interested in the currentTarget field. From it we will get a link to the element that was clicked:

Var toolbarButtonHandler = function(e) ( var button = e.currentTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); for(var i = 0; i< buttons.length; i++) { button.addEventListener("click", toolbarButtonHandler); }
Great! Not only have we simplified everything down to a single function that is used multiple times, we've also made our code more readable by removing an unnecessary generator function.

However, we can still do better.

Let's say we added some buttons to the sheet after our code had executed. Then we would also need to add event handlers for each of them. And we would have to store a link to this handler and links from other places. Doesn't look too tempting.

Perhaps there is another approach?

Let's start by understanding how events work and how they move along our DOM.

How do most of them work? When the user clicks on an element, an event is generated to notify the application about this. The journey of each event occurs in three stages:
  • Interception phase
  • Event occurs on the target element
  • Ascent phase
  • Note: not all events go through the interception or bubbling stage; some are created immediately on the element. However, this is rather an exception to the rule.

    The event is created outside the document and then sequentially moved through the DOM hierarchy to the target element. Once it has reached its target, the event is fetched from the DOM element in the same way.

    Here is our HTML template:

    • Button A
    • Button B
    • Button C

    When the user clicks on button A, the event travels like this:

    Start
    | #document
    | Interception phase
    | HTML
    | BODY
    | UL
    | LI#li_1
    | Button A< - Событие возникает для целевого элемента
    | Ascent phase
    | LI#li_1
    | UL
    | BODY
    | HTML
    v #document

    Notice that we can trace the path an event takes to reach its target element. In our case, for each button pressed, we can be sure that the event will bubble back up, passing through its parent - the ul element. We can use this and implement popup events.

    Bubble Events Bubble events are those events that are attached to a parent element, but are executed only if they satisfy some condition.

    Let's take our toolbar as a concrete example:

    Ul class="toolbar">

  • Pencil
  • Pen
  • eraser

  • Now that we know that any click on the button will pop up through the ul.toolbar element, let's attach our event handler to it. Fortunately, we already have it:

    Var toolbar = document.querySelector(".toolbar"); toolbar.addEventListener("click", function(e) ( var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. remove("active"); ));
    We now have much cleaner code, and we've even gotten rid of loops! Note however that we have replaced e.currentTarget with e.target . The reason lies in the fact that we process events at a different level.

    e.target is the actual target of the event, where it makes its way through the DOM, and where it will then bubble up from.
    e.currentTarget - the current element that handles the event. In our case, this is ul.toolbar.

    Improved Bubble Events this moment We handle any click on each element that pops up via ul.toolbar , but our validation condition is too simple. What would happen if we had a more complex DOM that included icons and elements that were not designed to be clicked?

    • Pencil
    • Pen
    • eraser

    Oops! Now when we click on the li.separator or icon, we add the .active class to it. At the very least, this is not good. We need a way to filter events so that we react to the element we need.

    Let's create a small helper function for this:

    Var delegate = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) continue; e.delegateTarget = el; listener.apply(this, arguments); return; ) while((el = el.parentNode)); ); );
    Our assistant does two things. First, it will iterate over each element and its parents and check if they satisfy the condition passed in the criteria parameter. If the element satisfies, the helper adds a field to the event object called delegateTarget, which stores the element that satisfies our conditions. And then calls the handler. Accordingly, if no element satisfies the condition, no handler will be called.

    We can use it like this:

    Var toolbar = document.querySelector(".toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var button = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("click", delegate(buttonsFilter, buttonHandler));
    Just what the doctor ordered: one event handler attached to one element that does all the work. But it does it only for the elements we need. And it responds perfectly to adding and removing objects from the DOM.

    Summing up We briefly reviewed the basics of implementing delegation (handling pop-up) events on pure JavaScript. This is good because we don't need to generate and attach a bunch of handlers for each element.

    If I wanted to make a library out of this or use the code in development, I would add a couple of things:

    A helper function for checking whether an object meets the criteria in a more unified and functional form. Like:

    Var criteria = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return criteria.isElement(e) && e.classList.contains(cls); ) ) //More criteria);
    Partial use of the assistant would also be useful:

    Var partialDelgate = function(criteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Original article: Understanding Delegated JavaScript Events
    (From the translator: my first, judge strictly.)

    Happy coding!

    Events are actions or occurrences that happen in the system you are programming, which the system tells you about so you can respond to them in some way if desired. For example, if the user clicks a button on a webpage, you might want to respond to that action by displaying an information box. In this article, we discuss some important concepts surrounding events, and look at how they work in browsers. This won't be an exhaustive study; just what you need to know at this stage.

    Prerequisites: Objective:
    Basic computer literacy, a basic understanding of HTML and CSS, JavaScript first steps.
    To understand the fundamental theory of events, how they work in browsers, and how events may differ in different programming environments.
    A series of fortunate events

    As mentioned above, events are actions or occurrences that happen in the system you are programming - the system produces (or "fires") a signal of some kind when an event occurs, and also provides a mechanism by which some kind of action can be automatically taken (that is, some code running) when the event occurs. For example in an airport when the runway is clear for a plane to take off, a signal is communicated to the pilot, and as a result, they commence piloting the plane.

    In the case of the Web, events are fired inside the browser window, and tend to be attached to a specific item that resides in it - this might be a single element, set of elements, the HTML document loaded in the current tab, or the entire browser window. There are a lot of different types of events that can occur, for example:

    • The user clicking the mouse over a certain element or hovering the cursor over a certain element.
    • The user pressing a key on the keyboard.
    • The user resizing or closing the browser window.
    • A form being submitted.
    • A video being played, or paused, or finishing play.
    • An error occurring.

    You can gather from this (and from glancing at the MDN Event reference) that there are a lot of events that can be responded to.

    Each available event has an event handler , which is a block of code (usually a JavaScript function that you as a programmer create) that will be run when the event fires. When such a block of code is defined to be run in response to an event firing, we say we are registering an event handler . Note that event handlers are sometimes called event listeners - they are pretty much interchangeable for our purposes, although strictly speaking, they work together. The listener listens out for the event happening, and the handler is the code that is run in response to it happening.

    Note: Web events are not part of the core JavaScript language - they are defined as part of the APIs built into the browser.

    A simple example

    Let's look at a simple example to explain what we mean here. You've already seen events and event handlers used in many of the examples in this course already, but let's recap just to cement our knowledge. In the following example , we have a single , which when pressed, makes the background change to a random color:

    Change color

    Button ( margin: 10px );

    The JavaScript looks like so:

    Const btn = document.querySelector("button"); function random(number) ( return Math.floor(Math.random() * (number+1)); ) btn.onclick = function() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; )

    In this code, we store a reference to the button inside a constant called btn , using the Document.querySelector() function. We also define a function that returns a random number. The third part of the code is the event handler. The btn constant points to a element, and this type of object has a number of events that can fire on it, and therefore, event handlers available. We are listening for the click event firing, by setting the onclick event handler property to equal an anonymous function containing code that generates a random RGB color and sets the background-color equal to it.

    This code is run whenever the click event fires on the element, that is, whenever a user clicks on it.

    The example output is as follows:

    It"s not just web pages

    Another thing worth mentioning at this point is that events are not unique to JavaScript - most programming languages ​​have some kind of event model, and the way the model works often differs from JavaScript"s way. In fact, the event model in JavaScript for web pages differs from the event model for JavaScript as it is used in other environments.

    Inline event handlers - don't use these

    You might also see a pattern like this in your code:

    Press me function bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; )

    The earliest method of registering event handlers found on the Web involved event handler HTML attributes (or inline event handlers ) like the one shown above - the attribute value is literally the JavaScript code you want to run when the event occurs. The above example invokes a function defined inside a element on the same page, but you could also insert JavaScript directly inside the attribute, for example:

    Press me

    You can find HTML attribute equivalents for many of the event handler properties; however, you shouldn't use these - they are considered bad practice. It might seem easy to use an event handler attribute if you are just doing something really quick, but they very quickly become unmanageable and ineffective.

    For a start, it is not a good idea to mix up your HTML and your JavaScript, as it becomes hard to parse - keeping your JavaScript all in one place is better; if it is in a separate file you can apply it to multiple HTML documents.

    Even in a single file, inline event handlers are not a good idea. One button is OK, but what if you had 100 buttons? You"d have to add 100 attributes to the file; it would very quickly turn into a maintenance. With JavaScript, you could easily nightmare add an event handler function to all the buttons on the page no matter how many there were, using something like this:

    Const buttons = document.querySelectorAll("button"); for (let i = 0; i< buttons.length; i++) { buttons[i].onclick = bgChange; } buttons.forEach(function(button) { button.onclick = bgChange; });

    Note: Separating your programming logic from your content also makes your site more friendly to search engines.

    addEventListener() and removeEventListener()

    The newest type of event mechanism is defined in the Document Object Model (DOM) Level 2 Events Specification, which provides browsers with a new function - addEventListener() . This functions in a similar way to the event handler properties, but the syntax is obviously different. We could rewrite our random color example to look like this:

    Const btn = document.querySelector("button"); function bgChange() ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body.style.backgroundColor = rndCol; ) btn.addEventListener("click", bgChange);

    Inside the addEventListener() function, we specify two parameters - the name of the event we want to register this handler for, and the code that comprises the handler function we want to run in response to it. Note that it is perfectly appropriate to put all the code inside the addEventListener() function, in an anonymous function, like this:

    Btn.addEventListener("click", function() ( var rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; document.body .style.backgroundColor = rndCol; ));

    This mechanism has some advantages over the older mechanisms discussed earlier. For a start, there is a counterpart function, removeEventListener() , which removes a previously added listener. For example, this would remove the listener set in the first code block in this section:

    Btn.removeEventListener("click", bgChange);

    This isn't significant for simple, small programs, but for larger, more complex programs it can improve efficiency to clean up old unused event handlers. Plus, for example, this allows you to have the same button performing different actions in different circumstances - all you have to do is add or remove event handlers as appropriate.

    Second, you can also register multiple handlers for the same listener. The following two handlers wouldn't both be applied:

    MyElement.onclick = functionA; myElement.onclick = functionB;

    The second line overwrites the value of onclick set by the first line. This would work, however:

    MyElement.addEventListener("click", functionA); myElement.addEventListener("click", functionB);

    Both functions would now run when the element is clicked.

    In addition, there are a number of other powerful features and options available with this event mechanism. These are a little out of scope for this article, but if you want to read up on them, have a look at the addEventListener() and removeEventListener() reference pages.

    What mechanism should I use?

    Of the three mechanisms, you definitely shouldn't use the HTML event handler attributes - these are outdated, and bad practice, as mentioned above.

    The other two are relatively interchangeable, at least for simple uses:

    • Event handler properties have less power and options, but better cross-browser compatibility (being supported as far back as Internet Explorer 8). You should probably start with these as you are learning.
    • DOM Level 2 Events (addEventListener() , etc.) are more powerful, but can also become more complex and are less well supported (supported as far back as Internet Explorer 9). You should also experiment with these, and aim to use them where possible.

    The main advantages of the third mechanism are that you can remove event handler code if needed, using removeEventListener() , and you can add multiple listeners of the same type to elements if required. For example, you can call addEventListener("click", function() ( ... )) on an element multiple times, with different functions specified in the second argument. This is impossible with event handler properties because any subsequent attempts to set a property will overwrite earlier ones, e.g.:

    Element.onclick = function1; element.onclick = function2; etc.

    Note: If you are called upon to support browsers older than Internet Explorer 8 in your work, you may run into difficulties, as such ancient browsers use different event models from newer browsers. But never fear, most JavaScript libraries (for example jQuery) have built-in functions that abstract away cross-browser differences. Don't worry about this too much at this stage in your learning journey.

    Other event concepts

    In this section, we briefly cover some advanced concepts that are relevant to events. It is not important to understand these concepts fully at this point, but they might serve to explain some code patterns you"ll likely come across from time to time.

    Event objects

    Sometimes inside an event handler function, you might see a parameter specified with a name such as event , evt , or simply e . This is called the event object , and it is automatically passed to event handlers to provide extra features and information. For example, let's rewrite our random color example again slightly:

    Function bgChange(e) ( const rndCol = "rgb(" + random(255) + "," + random(255) + "," + random(255) + ")"; e.target.style.backgroundColor = rndCol ; console.log(e); ) btn.addEventListener("click", bgChange);

    Here you can see that we are including an event object, e , in the function, and in the function setting a background color style on e.target - which is the button itself. The target property of the event object is always a reference to the element that the event has just occurred upon. So in this example, we are setting a random background color on the button, not the page.

    Note : You can use any name you like for the event object - you just need to choose a name that you can then use to reference it inside the event handler function. e/evt/event are most commonly used by developers because they are short and easy to remember. It"s always good to be consistent - with yourself, and with others if possible.

    e.target is incredibly useful when you want to set the same event handler on multiple elements and do something to all of them when an event occurs on them. You might, for example, have a set of 16 tiles that disappear when they are clicked on. It is useful to always be able to just set the thing to disappear as e.target , rather than having to select it in some more difficult way. In the following example (see useful-eventtarget.html for the full source code; also see it running live here), we create 16 elements using JavaScript. We then select all of them using document.querySelectorAll() , then loop through each one, adding an onclick handler to each that makes it so that a random color is applied to each one when clicked:

    Const divs = document.querySelectorAll("div"); for (let i = 0; i< divs.length; i++) { divs[i].onclick = function(e) { e.target.style.backgroundColor = bgChange(); } }

    The output is as follows (try clicking around on it - have fun):

    Hidden example Useful event target example div ( height: 100px; width: 25%; float: left; ) for (let i = 1; i
  • Pencil
  • Pen
  • eraser

  • Now that we know that any click on the button will pop up through the ul.toolbar element, let's attach our event handler to it. Fortunately, we already have it:

    Var toolbar = document.querySelector(".toolbar"); toolbar.addEventListener("click", function(e) ( var button = e.target; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList. remove("active"); ));
    We now have much cleaner code, and we've even gotten rid of loops! Note however that we have replaced e.currentTarget with e.target . The reason lies in the fact that we process events at a different level.

    e.target is the actual target of the event, where it makes its way through the DOM, and where it will then bubble up from.
    e.currentTarget - the current element that handles the event. In our case, this is ul.toolbar.

    Improved popup events Currently we handle any click on each element that pops up via ul.toolbar , but our validation condition is too simple. What would happen if we had a more complex DOM that included icons and elements that were not designed to be clicked?

    • Pencil
    • Pen
    • eraser

    Oops! Now when we click on the li.separator or icon, we add the .active class to it. At the very least, this is not good. We need a way to filter events so that we react to the element we need.

    Let's create a small helper function for this:

    Var delegate = function(criteria, listener) ( return function(e) ( var el = e.target; do ( if (!criteria(el)) continue; e.delegateTarget = el; listener.apply(this, arguments); return; ) while((el = el.parentNode)); ); );
    Our assistant does two things. First, it will iterate over each element and its parents and check if they satisfy the condition passed in the criteria parameter. If the element satisfies, the helper adds a field to the event object called delegateTarget, which stores the element that satisfies our conditions. And then calls the handler. Accordingly, if no element satisfies the condition, no handler will be called.

    We can use it like this:

    Var toolbar = document.querySelector(".toolbar"); var buttonsFilter = function(elem) ( return elem.classList && elem.classList.contains("btn"); ); var buttonHandler = function(e) ( var button = e.delegateTarget; if(!button.classList.contains("active")) button.classList.add("active"); else button.classList.remove("active" ); ); toolbar.addEventListener("click", delegate(buttonsFilter, buttonHandler));
    Just what the doctor ordered: one event handler attached to one element that does all the work. But it does it only for the elements we need. And it responds perfectly to adding and removing objects from the DOM.

    Summing up We briefly looked at the basics of implementing delegation (handling pop-up) events in pure JavaScript. This is good because we don't need to generate and attach a bunch of handlers for each element.

    If I wanted to make a library out of this or use the code in development, I would add a couple of things:

    A helper function for checking whether an object meets the criteria in a more unified and functional form. Like:

    Var criteria = ( isElement: function(e) ( return e instanceof HTMLElement; ), hasClass: function(cls) ( return function(e) ( return criteria.isElement(e) && e.classList.contains(cls); ) ) //More criteria);
    Partial use of the assistant would also be useful:

    Var partialDelgate = function(criteria) ( return function(handler) ( return delgate(criteria, handler); ) );
    Original article: Understanding Delegated JavaScript Events
    (From the translator: my first, judge strictly.)

    Happy coding!

    Hello! In this lesson I want to talk about such an important concept as surfacing and interception of events. Bubbling is a phenomenon where if you click on a child element, the event propagates to its parent.

    It can be very useful when processing large nested lists or tables; in order not to assign an event handler to each element, you can assign one handler to the parent element, and the event will already propagate to all nested elements in the parent. Let's look at an example.

    This handler will fire if you click on a subtag or :

    Click on EM, the handler on DIV will work

    As you can see, when you click on a nested em element, the handler on the div is triggered. Why is this happening? Read on and find out.

    Ascent

    So the basic principle of ascent:

    When there is an event of any kind, it doesn’t matter if the mouse is clicked on an element, the event will first fire on the parent element, and then along the chain it will propagate to all nested elements.

    For example, suppose there are 3 nested elements FORM > DIV > P, with an event handler on each:

    body * ( margin: 10px; border: 1px solid blue; ) FORM DIV

    Bubbling ensures that clicking on the inner element

    Will call the click handler (if there is one of course) first on the actual

    This process is called ascent, because events seem to “float up” from the internal element upward through their parents, just as an air bubble floats up in water, so you can also find the definition of bubbling, well, it’s just from the English word bubbling - to float up.

    Accessing the target element event.target

    In order to find out on which element we caught this or that event, there is the event.target method. (read about the event object).

    • event.target is the actual source element on which the event occurred.
    • this is always the current element that the bubbling has reached, and the handler is currently running on it.

    For example, if you have only one form.onclick handler installed, then it will “catch” all clicks inside the form. Moreover, no matter where the click is inside, it will still pop up to the element, on which the handler will work.

    Wherein:

    • this (=event.currentTarget) will always be the form itself, since the handler was triggered on it.
    • event.target will contain a link to a specific element within the form, the most nested one on which the click occurred.

    In principle, this can coincide with event.target if the form is clicked and there are no more elements in the form.

    Stopping ascent

    Typically, the event bubbling goes straight to the top and reaches the root window object.

    But it is possible to stop the ascent at some intermediate element.

    In order to stop propagation, you need to call the event.stopPropagation() method.

    Let's look at an example: when a button is clicked, the body.onclick handler will not work:

    Click me

    If an element has several handlers installed for the same event, then even if bubbling stops, all of them will be executed.

    Thus, stopPropagation will prevent the event from propagating further, but all handlers will work on the element, but not on the next element.

    To stop processing on the current element, browsers support the event.stopImmediatePropagation() method. This method will not only prevent bubbling, but will also stop event processing on the current element.

    Dive

    In the standard, in addition to the “ascent” of events, there is also a “dive”.

    Diving, unlike ascent, is less in demand, but it will still be useful to know about it.

    So there are 3 stages of the event:

  • The event comes from top to bottom. This stage is called the "interception stage".
  • The event reached a specific element. This is the “goal stage”.
  • After everything, the event begins to emerge. This is the “ascent stage”.
  • This is demonstrated in the standard as follows:

    Thus, when you click on the TD, the event will travel along the chain of parents, first down to the element (“sinks”), and then up (“pops up”), using handlers accordingly along the way.

    Above I wrote only about ascent, because the other stages are not used and pass unnoticed by us.

    The handlers do not know anything about the interception stage, but start working from the ascent.

    And to catch an event at the interception stage, you just need to use:

    • The argument is true, then the event will be intercepted on the way down.
    • The argument is false, then the event will be caught when bubbling.
    Examples

    In the example at , ,

    The processors are the same as before, but this time at the immersion stage. Well, to see interception in action, click on the element in it

    The handlers will work in top-down order: FORM → DIV → P.

    The JS code here is:

    Var elems = document.querySelectorAll("form,div,p"); // attach a handler to each element at the interception stage for (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); }


    No one is stopping you from assigning handlers for both stages, like this:

    Var elems = document.querySelectorAll("form,div,p"); for (var i = 0; i< elems.length; i++) { elems[i].addEventListener("click", highlightThis, true); elems[i].addEventListener("click", highlightThis, false); }

    Click on the inner element

    To see the order of events:
    It should be FORM → DIV → P → P → DIV → FORM. Note that the element

    Will participate in both stages.

    Results
    • When an event occurs, the element on which the event occurred is marked as event.target.
    • The event first moves down from the document root to event.target, calling handlers along the way, supplied via addEventListener(…., true).
    • The event moves from event.target up to the beginning of the document, along the way it calls handlers supplied via addEventListener(…., false).

    Each handler will have access to the event properties:

    • event.target is the deepest element where the event actually occurred.
    • event.currentTarget (=this) – the element on which the self-handler is currently triggered (to which the event has “reached”).
    • event.eventPhase – at what phase the event handler was triggered (dive = 1, ascend = 3).

    Propagation can be stopped by calling the event.stopPropagation() method, but this is not recommended, since you may need the event for the most unexpected purposes.