Can you give an example of a typical line of jQuery that you prefer over vanilla?
Can you give an example of a typical line of jQuery that you prefer over vanilla?
https://connect.microsoft.com/IE/feedback/details/878564/ele...
With jQuery I'd often do
$(<root-element>).on('click', <target element>, callback);
crucially, because events bubble up, even a click on a child element of <target element> will register as a click on the target element.in plain js it doesn't seem to work that way. I'd do <root-elem>.addEventListener(), but I'd run into the problem that the event.target would point at the exact element that was clicked on instead of the parent element that I wanted to register clicks on.
Given the structure ".item .inner .title", I can't just check if event.target.classList contains 'item', because it might only contain 'title' or 'inner'.
event.path to the rescue! I can simply check if any of the parent nodes do contain the 'item' class. Except event.path doesn't work in safari mobile, so it needs a polyfill. Plus on every event handler I have to go up event.path to check.
Obviously it's not that hard to write a helper function that basically emulates .on(), but I can't help but feel that I'm maybe missing some simpler, plain solution. Any suggestions?
Unless I misunderstand, I think you might be looking for "event.currentTarget". event.target is the element that was clicked on, event.currentTarget is the element that has the event listener attached.
<root-element>
.querySelector(<target element>)
.addEventListener('click', function(event){
// event.currentTarget refers to
// <target element> no matter which of its
// children were clicked
});
Admittedly, this doesn't work as well for multiple target elements. I use a forEach polyfill which could loop through them, but that could create a lot of event listeners when possibly you'd only need one higher up. Depends how many there are, I suppose.This is why one of the early lessons you learn as a jQuery user is to use $().on() instead of something like $().click();
Plus, while I don't suppose it's a real performance issue much of the time, adding an event listener to each of, say, a few hundred items in a list is probably rather inefficient compared to adding it to the root element of the list.
function delegate(el, evt, sel, handler) {
el.addEventListener(evt, function (event) {
let t = event.target
while (t && t !== this) {
if (t.matches(sel)) {
handler.call(t, event)
}
t = t.parentNode
}
})
}
delegate(document, 'click', '[data-behavior="open"]', function (event) {
event.preventDefault()
})You'll need a matches polyfill if supporting browsers that don't support el.matches
In jQuery I can do something like this:
$(<Carousel>).on('click', <Item>, function(e) {
// using this 'this' gives you the <Item> element. Always. Even
// if you click on a child element of <Item>. And it works if
// you add or remove items. Also it doesn't add a listener
// to *every* single item, which matters if you've got a whole
// bunch of them!
});
The vanilla equivalent is often presented to be as simple as: <Carousel>.addEventListener('click', function(e) {
// e.target is the actual element you clicked. So now we need to
// figure out if this element is inside an <Item>, and perhaps
// also *which* <Item>. There's various approaches, and it's
// not rocket science, but it's all extra work for something that
// seems like a common scenario.
});