Search code examples
javascriptjquerydelegation

Javascript Delegation Best Practice


I am developing/have developed a few systems now, I have come across a querk in my programming, I seem to delegation all my JQuery functions to the document like so:

$(document).on('click', '.modal-editor', function () {
    //code
});

$(document).on('click', '.another-class', function () {
    //code
});

$(document).on('click', '#another-id', function () {
    //code
});

Is there anything wrong with this?

UPDATE:

Ok so in essence there is nothing wrong with this until:

  1. The applications reaches a scale where delegation needs to be more localised to prevent slowing down UI. "Every event that takes place needs to run every selector against every element between the e.target and the document"

  2. Delegation like this will increase the chances of unexpected behaviour like propagation if nested functions are used.

Referring back to my question (best practice), best practice would be to delegate the event to the closest static element as possible to attempt to avoid the above.


Solution

  • Yes. In itself there isn't, nto really, but delegating all events from the document (root of the DOM) does meant that all click events, including those you're not interested in will be handled at least partially:

    $(document).on('click', '$another-id', function(){});
    

    is a particularly bad idea, in that respect: you're after a single element, but if I click anywhere in the body, jQ will do something like:

    if (event.target.id == 'another-id')
    {
        return callback.call(event.target, $(event));//where callback is the anonymous function you passed to on
    }
    return event;
    

    So all click events result in a function call. This can slow your UI down.
    By no means should you stop delegating events, but bind the listeners wisely. If all the DOM elements you want to use are contained within the #container div, for example, then bind your listeners there. If you want to handle navigation events, bind the listener to the node that contains all the navigation elements your after
    Add to that that, if you cancel an event, but failed to stopPropagation, the event will still end up invoking all your other listeners that might be queued. Returnign false can also cause trouble, seeing as, in jQ, return false is translated to e.preventDefault(); e.stopPropagation(). So be careful when dealing with nested elements, if you want to handle a click on links in your page, but also on elements like <a class='navigation'>, both handlers might be called, depending on the selectors used:

    $(document).on('click', 'a', function(){});//is called for all links
    $(document).on('click', 'a.navigation', function(){});//is called for navigation
    

    Which will be invoked first? Which would you want to use in a given situation? There's room for error here, that shouldn't be there:

    $('#navContainer').on('click', 'a.navigation', function(){});//is called for all links
    

    At least makes things a tad safer, clearer and lighter, too.

    If you want to delegate an event, using an ID selector, and the element already exists in the DOM, don't delegate:

    $('#another-id').on('click', function(){});
    

    is shorter, and will likely even be faster anyway