28
votes

Does anyone know how jQuery's .on() method can be implemented in native JS? The addEventListener method does not take a child/selector element as a way to filter, and I don't think I have the proper bubbling/capturing knowledge to completely understand what is happening in there. I did consult the source in event.js, where it appears that eventually addEventListener does get used just as it normally does, but I'm not sure I quite grok the source.

If the native method does not provide a mechanism for taking advantage of bubbling and capturing, then does the jQuery .on() function really even have any benefit, or does it just make it look that way? I was under the impression that

.on('parent', '.child', fn(){});

is more efficient than attaching an event to all children individually, but from my interpretation of the source, it's difficult to tell if jQuery is somehow managing this in a way to leads to performance improvement, or if it's just for readability.

Is there a standard methodology for implementing events on a parent that take advantage of bubbling/capture phases for it's child elements, rather than having to attach an event to each individual child?

1
If you didn't understand how .on() works then I doubt that you can actually judge the performance of itAlexander
To learn everything you need to know about events: quirksmode.org/js/introevents.html. Regarding your question: What you want is called event delegation and it's actually pretty simple. Attach an even handler to any parent and check whether the target node (event.target) fullfils your criteria.Felix Kling

1 Answers

25
votes

To perform event delegation natively:

parent.addEventListener('click', function(e) {
    if(e.target.classList.contains('myclass')) {
        // this code will be executed only when elements with class 
        // 'myclass' are clicked on
    }
});

The efficiency you are referring to has to do with how many event handlers you add. Imagine a table with 100 rows. It is much more efficient to attach a single event handler to the table element then 'delegate' to each row than attach 100 event handlers, 1 to each row.

The reason event delegation works is because a click event actually fires on both the child and the parent (because you're clicking over a region within the parent). The above code snippet fires on the parent's click event, but only executes when the condition returns true for the event target, thus simulating a directly attached event handler.

Bubbling/capturing is a related issue, but you only need to worry about it if the order of multiple event handlers firing matters. I recommend reading further on event order if you are interested in understanding bubbling vs capturing.

The most common benefit of event delegation is that it handles new elements that are added to the DOM after the event handler is attached. Take the above example of a table of 100 rows with click handlers. If we use direct event handler attachment (100 event handlers), then new rows that are added will need event handlers added manually. If we use delegated events, then new rows will automatically 'have' the event handler, because it's technically been added to the parent which will pick up all future events. Read What is DOM Event Delegation, as Felix Kling suggested, for more information.