2

I hate jQuery. Unfortunately, it's used a lot in one of my work's largest projects and I cringe every time I have to deal with it. I'm currently in the long overdue process of upgrading a lot of the JavaScript (and migrating to TypeScript) and there's one piece of jQuery I'm not so sure how to best replace.

The method in question would be jQuery's on(events [, selector] [, data] [, handler ]) method. It allows you to create event listeners for a selector, before any elements matching the selector have been added to the DOM. As far as jQuery methods go, this one isn't bad.

To replace it, my first thought would be to use something like this:

function on(event, selector, handler) {
    addEventListener(event, ev => {
        if (ev.target.matches(selector)) {
            handler()
        }
    }
}

That doesn't look too efficient in my opinion and I'm unsure if it's the best way to replace the method. Am I correct in my thoughts and if so, what would be the best way to replace the method?

8
  • First thing that I notice: the functioning of jQuery's on depends on the this object (the jQuery object on which on is called). I don't see this covered in your attempt.
    – trincot
    Commented May 18, 2022 at 11:21
  • @trincot Sorry, I should have been more precise in my question. If I was to actually implement what I wrote, I would of course bind it to the targeted element so this could be used within the handler. I'm not trying to replicate jQuery, but find the best way to replace it without impacting too much.
    – Spedwards
    Commented May 18, 2022 at 11:23
  • It goes further than you say. addEventListener should be called on the target element, not (necessarily) on the window object. You would need to translate whatever is selected as jQuery object to an equivalent implementation (an argument? Or are you going to use call(thisArg, ...)?
    – trincot
    Commented May 18, 2022 at 11:26
  • @trincot I would have used handler.bind(ev.target, ev) more than likely. Bind it to the target and pass through the event.
    – Spedwards
    Commented May 18, 2022 at 11:28
  • 1
    For what it is worth, this is the implementation of on from jQuery. It uses other jQuery stuff, so it can't be adopted directly, but it might be useful to get an idea of how it woks. Commented May 18, 2022 at 11:39

1 Answer 1

3

matches will not work in all cases. For example, consider the following snippet. Clicking on the span element within the button will not trigger the handler.

function on(event, elem, selector, handler) {
    elem.addEventListener(event, ev => {
        if (ev.target.matches(selector)) {
            handler()
        }
    })
}
on('click', document.querySelector('#test'), 'button', () => console.log('Clicked'));
<div id="test">
    <button>Click Me <i class="icon icon-something">&rarr;</i></button>
</div>

This can be fixed by replacing matches with closest. I have also updated the handler invocation to set this to the matched target element.

function on(event, elem, selector, handler) {
    elem.addEventListener(event, ev => {
        const target = ev.target.closest(selector);
        if (target) {
            handler.apply(target, arguments)
        }
    })
}
on('click', document.querySelector('#test'), 'button', function () { console.log('Clicked ' + this.tagName);});
<div id="test">
    <button>Click Me <i class="icon icon-something">&rarr;</i></button>
</div>

Not the answer you're looking for? Browse other questions tagged or ask your own question.