JavaScript - Event Bubbling. Introduction to bubbling events Canceling event bubbling js

It all started with using 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 include jQuery libraries for "this little test", just to use the event bubbles.

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. At least not in the way we expect.

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's ours 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.

    As concrete example Let's take our toolbar:

    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 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 this 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, so as 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 an event occurs, no matter if the mouse is clicked on an element, the event will first fire on the parent element, and then propagate along the chain 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 actually source element, where the event took place.
    • 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.

    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. We will insert the script written in JavaScript 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 the 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 keyword this. This 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 the window object to the 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 is obtained:

    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 an event on the target itself, you can use the addEventListener method with either the false or true value.

    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:

    Event interception

    One of the important features of the language is event interception. If someone clicks a button, for example, the onClick event handler corresponding to that button is called. With event handling, you can ensure that the object corresponding to your window, document, or layer intercepts and processes an event before the event handler is called for that purpose by the specified button object. Likewise, your window, document, or layer object can process an event signal before it even reaches its normal destination.
    To see what this might be useful for, let's look at the following example:



    window.onclick=handle;

    function handle(e) (
    alert("The window object is intercepting this event!");
    return true; // i.e. follow link
    }




    Click on this link

    As you can see, we do not specify event handlers in the tag . Instead we write

    window.captureEvents(Event.CLICK);

    in order to intercept the event Click window object. Normally the window object doesn't work with the event Click. However, having intercepted it, we will then redirect it to the window object. Note that in Event.CLICK fragment CLICK must be written in capital letters. If you want to intercept several events, then you should separate them from each other with the | symbols. For example:

    window.captureEvents(Event.CLICK | Event.MOVE);

    In addition to this, in the function handle(), which we have assigned to the role of event handler, we use the instruction return true;. What this actually means is that the browser must process the link itself after the function completes. handle(). If you write instead return false;, then this will all end.

    If now in the tag You will specify an event handler onClick, you will understand that this program will no longer be called when this event occurs. This is not surprising, since the window object intercepts the event signal before it even reaches the link object. If you define a function handle() How

    function handle(e) (
    alert("The window object captured this event!");
    window.routeEvent(e);
    return true;
    }

    then the computer will check whether other event handlers are defined for this object. The variable e is our Event object, passed to the event function as an argument.

    In addition, you can directly send an event signal to an object. To do this you can use the method handleEvent(). It looks like this:


    window.captureEvents(Event.CLICK);

    window.onclick=handle;

    function handle(e) (
    document.links.handleEvent(e);
    }


    "Click" on this link

    Second link

    All Click event signals are sent to the second link for processing - even if you didn't click on any of the links at all!

    The following script demonstrates how your script can respond to keypress signals. Press any key and see how this script works.


    window.captureEvents(Event.KEYPRESS);

    window.onkeypress= pressed;

    function pressed(e) (
    alert("Key pressed! ASCII-value: " + e.which);
    }

    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 include jQuery libraries for "this little test", just to use the event bubbles.

    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. At least not in the way we expect.

    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 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!