jQuery API

.delegate()

.delegate( selector, eventType, handler(eventObject) ) Returns: jQuery

Description: Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.

  • version added: 1.4.2.delegate( selector, eventType, handler(eventObject) )

    selectorA selector to filter the elements that trigger the event.

    eventTypeA string containing one or more space-separated JavaScript event types, such as "click" or "keydown," or custom event names.

    handler(eventObject)A function to execute at the time the event is triggered.

  • version added: 1.4.2.delegate( selector, eventType, eventData, handler(eventObject) )

    selectorA selector to filter the elements that trigger the event.

    eventTypeA string containing one or more space-separated JavaScript event types, such as "click" or "keydown," or custom event names.

    eventDataA map of data that will be passed to the event handler.

    handler(eventObject)A function to execute at the time the event is triggered.

  • version added: 1.4.3.delegate( selector, events )

    selectorA selector to filter the elements that trigger the event.

    eventsA map of one or more event types and functions to execute for them.

As of jQuery 1.7, .delegate() has been superseded by the .on() method. For earlier versions, however, it remains the most effective means to use event delegation. More information on event binding and delegation is in the .on() method. In general, these are the equivalent templates for the two methods:

$(elements).delegate(selector, events, data, handler);  // jQuery 1.4.3+
$(elements).on(events, selector, data, handler);        // jQuery 1.7+
 

For example, the following .delegate() code:

$("table").delegate("td", "click", function() {
  $(this).toggleClass("chosen");
});

is equivalent to the following code written using .on():

$("table").on("click", "td", function() {
  $(this).toggleClass("chosen");
});

To remove events attached with delegate(), see the .undelegate() method.

Passing and handling event data works the same way as it does for .on().

Additional Notes:

  • Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will propagate to the elements to which they are delegated; event handlers bound on any elements below it in the DOM tree will already have been executed by the time the delegated event handler is called. These handlers, therefore, may prevent the delegated handler from triggering by calling event.stopPropagation() or returning false.

Examples:

Example: Click a paragraph to add another. Note that .delegate() attaches a click event handler to all paragraphs - even new ones.

<!DOCTYPE html>
<html>
<head>
  <style>
  p { background:yellow; font-weight:bold; cursor:pointer; 
      padding:5px; }
  p.over { background: #ccc; }
  span { color:red; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <p>Click me!</p>

  <span></span>
<script>
    $("body").delegate("p", "click", function(){
      $(this).after("<p>Another paragraph!</p>");
    });
</script>

</body>
</html>

Demo:

Example: To display each paragraph's text in an alert box whenever it is clicked:

$("body").delegate("p", "click", function(){
  alert( $(this).text() );
});

Example: To cancel a default action and prevent it from bubbling up, return false:

$("body").delegate("a", "click", function() { return false; })

Example: To cancel only the default action by using the preventDefault method.

$("body").delegate("a", "click", function(event){
  event.preventDefault();
});

Example: Can bind custom events too.

<!DOCTYPE html>
<html>
<head>
  <style>
  p { color:red; }
  span { color:blue; }
  </style>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  <p>Has an attached custom event.</p>
  <button>Trigger custom event</button>
  <span style="display:none;"></span>
<script>

    $("body").delegate("p", "myCustomEvent", function(e, myName, myValue){
      $(this).text("Hi there!");
      $("span").stop().css("opacity", 1)
               .text("myName = " + myName)
               .fadeIn(30).fadeOut(1000);
    });
    $("button").click(function () {
      $("p").trigger("myCustomEvent");
    });

</script>

</body>
</html>

Demo:

Support and Contributions

Need help with .delegate() or have a question about it? Visit the jQuery Forum or the #jquery channel on irc.freenode.net.

Think you've discovered a jQuery bug related to .delegate()? Report it to the jQuery core team.

Found a problem with this documentation? Report it to the jQuery API team.

* All fields are required
  • ivanbone

    $(“body”).delegate(“p”,….

    Does this means that only one single event will be attached to instead of every inside ?

  • http://www.learningjquery.com/ Karl Swedberg

    yes

  • hairiemx

    what event are supported?

  • http://www.learningjquery.com/ Karl Swedberg

    all of them

  • http://twitter.com/mpodonyi Mike Podonyi

    The example which compares delegate with live is strange. Why not just writing the following in live. Its much easier then to use delegate.

    $(“table td”).live(“hover”, function(){
    $(this).toggleClass(“hover”);
    });

  • Michael

    Agree with you Mike !

    What is the advantage of these new methods, except that of making the user really confused with these 10 ways to write the same code?

    BTW, delegate/undelegate syntax sucks..

    $(“p”).undelegate() that remove event “of” each
    $(“p”).delegate(..) that add event to element “inside of”

    No sense !

  • Michael

    Should read

    $(“p”).undelegate() that remove event “of” each <p>
    $(“p”).delegate(..) that add event to element “inside of” <p>

  • http://twitter.com/frickenate Nate

    What it comes down to is that $('table td').live(); and $('table').delegate('td'); are *not* the same thing. The version with live() will only attach a single event to the document node (and thus automatically applies to any new tables dynamically added after page load), while the delegate() version will register a separate event listener for each table node found in the document at the time delegate() is called (therefore only applying to new TDs added to the existing tables, not new tables added later).

    delegate() was added for 2 reasons:

    1. delegate() is more efficient than live() when used for identical purposes. When you do $('table td').live(), jQuery wastefully searches the document for all 'table td' nodes and passes them to live(). This is “bad”, because live() *does not need* this list of nodes. The event is actually attached to the context node (the second argument passed to live(), which defaults to the document). live() does nothing with the list of 'table td' nodes that jQuery generates, thus the time/cpu spent finding these nodes is wasteful. $(document).delegate('table td') on the other hand simply needs to fetch the document node – no search for 'table td' nodes is done, as delegate() only uses that selector to handle delegation after an event is actually triggered.

    2. The syntax for passing a different context node to live() is ugly – delegate() provides a more legible approach. The equivalent of $('#single-table').delegate('td', …); with live() is $('td', $('#single-table')[0]).live(…); – not pretty.

    From a performance standpoint, you're better off no longer using live() at all, and to always use delegate().

    OLD: $('table td').live('click', fn); // wasted cycles for finding 'table td' nodes
    NEW: $(document).delegate('table td', 'click', fn); // no wasted cycles

    I think the confusion is with people not understanding the use cases or benefits of attaching events to a context other than document. Those who think of live() as only a way to apply events to nodes dynamically applied across the entire document after page load won't see the point of delegate(), except perhaps for the performance boost.

  • Shawn

    Its probably out of scope for jquery, but I would love to be able to have something similar that fires when a class name is added or removed to the selector. I guess it would technically be on a property change.

  • http://twitter.com/heyotwell heyotwell

    It’s really not two different ways to write the same code. These are two techniques that work for different situations.

    Think of .live() like this: $(“p”).live(click, fn) means “Attatch my fn function as a click event for every p tag in the document, even ones that get created later.” That attaches a copy of your function to every p tag, even if there are thousands of them in the document; potentially VERY memory-consuming. Every p element carries around its own copy of your fn function.

    .delegate() is *very* different. $(“#myelement p”).delegate(click, fn) means “attach my fn function to the #myelement element”. That’s ONE copy of the fn function exists, even if there are thousands of p tags under #myelement. It’s actually #myelement that catches the click, and checks to see “was this click on one of my p tags?” If so, it runs the function. That’s super cheap memory-wise, since there’s only one fn function floating around.

    When would you use .live() vs. .delegate()? Nate points out that the syntax is simpler and performance is better with .delegate() so it’s hard to really say when .live() might be better. It might be more understandable code-wise sometimes to use .live(), but it sounds like even that’s probably not worth it.

    There’s a lot of good articles about event delegation (though they don’t cover this brand new .delegate() method). Try this one by Karl Swedenberg for example.

  • http://twitter.com/frickenate Nate Bessette

    Whoa whoa whoa. Your examples and description of both live() and delegate() are wrong. delegate() and live() are *not* “very different”, and *are* fundamentally “two different ways to write the same code”. I suggest reading the documentation for live() and delegate() again, and correcting your post so not as to misguide/confuse others.

    a) $(‘p’).live(‘click’, fn); does *NOT* attach a copy of the fn to every p tag. It only adds a single event listener to the document node, and uses event delegation via bubbling to detect clicks on any p tag.

    b) $(‘#myelement p’).delegate(‘click’, fn); is simply not valid jQuery – you’re missing the first argument to delegate(). You must have meant $(‘#myelement’).delegate(‘p’, ‘click’, fn);, which would do just as you describe.

    As the release notes for 1.4.2 state, $(‘p’).live(‘click’, fn); is “roughly equivalent” to $(document).delegate(‘p’, ‘click’, fn);. With the rewrite of the event system, apparently delegate() no longer simply wraps live() as it did originally, so I’m not sure exactly how “equivalent” they are at this point in terms of internal functionality or performance. However, they do accomplish the exact same task.

  • http://twitter.com/mpodonyi Mike Podonyi

    I see your point.

    But i would write this in the documentation and explain exactly the difference and use cases of live and delegate.

    Without an exact explanation of the advantage no one will use delegate and will stick with live. Just because we are unsure about the new stuff.

  • Jan

    I am using jQuery in an environment with struts2 and also dojo (the mess is included in struts2). I try to avoid my problems with dojo through using jQuery – and I am curious, if the delegate function works only for dom modifications with jQuery?

    Reason – I have some server side tags that create dojo widgets and load content with ajax calls – and cause struts dojo has the issue, that if you got some of those widgets nested, javascript is not executed inside the returned content.

    As I need to sort a table (using jQuery tablesorter) i wanted to add something like
    jQuery(‘table’).delegate(‘#tblData’, ‘ready’, function() {
    jQuery(“#tblData”).tablesorter({
    sortList: [[4,1]],
    headers: {
    4: {
    sorter: ‘germandatetime’
    }
    }
    });
    });
    or am I wrong with what I try?

    Maybe someone can give me a hint on using this.
    Thanks in advance.

  • Anonymous

    I am experiencing the same thing. I am using Jquery on a site that also uses another library and when items are added using the other library the event attached using Jquery doesn’t get fired.

  • Anonymous

    I’m pretty excited about the new delegate methods, but someone should write some proper explanation on how to distinguish live and delegate methods

  • Tagny

    I was using the simple:
    $(“#someID div.someClass”).click(function(e){ … });
    with:
    e.preventDefault();
    inside the function block and it was working well.

    I converted to use:
    $(“#someID”).delegate(“div.someClass, “click”, function(e) { … });

    I am still keeping the ‘e.preventDefault();’ but it no longer prevents the events from leaking down. Does delegate treat events differently? If so, how? And, more importantly, how can we prevent events from propagating further when using delegate?

  • http://twitter.com/heyotwell heyotwell

    Ah, wow, I’m totally wrong! I don’t see any way to edit or delete my comment though.

  • http://www.learningjquery.com/ Karl Swedberg

    Take a look at the Live Query plugin:
    http://github.com/brandonaaron/livequery

  • http://www.speednet.biz/ Speednet

    Nate,

    According to all the examples of delegate() I’ve seen, the best approach is:

    $(‘table’).delegate(‘td’, ‘click’, fn);

    Are you saying that using $(document) as a starting point is better and/or faster?

    Thanks for clarifying.

  • Anonymous

    Does this function return the root elements or the elements that match the selector?

  • gadelkareem

    The documentation does not specify all the events supported by delegate() function!
    what about custom events like 'focusin' ,'focusout',….supported by live()

  • Anonymous

    Does it work with form submit events? And, about IE7+?

  • http://gadelkareem.com/ Waleed Gadelkareem

    Which events does delegate() supports?? same as live()? what about focusin, focusout?

  • The_BFG

    See Caveats in the docs for .live method…

    * As of jQuery 1.4 the .live() method supports custom events as well as all JavaScript events. As of jQuery 1.4.1 even focus and blur work with live (mapping to the more appropriate, bubbling, events focusin and focusout).
    * As of jQuery 1.4.1 the hover event can be specified (mapping to “mouseenter mouseleave”).

  • http://gadelkareem.com/ Waleed Gadelkareem

    and these custom events are supported by delegate() ?????

  • http://paulirish.com Paul Irish

    yes.

  • http://paulirish.com Paul Irish

    yes

  • http://paulirish.com Paul Irish

    it returns a jquery object of the root element(s).

  • Anonymous

    Depends on the case – if in your example $(‘table’) represents only 1 to a few tables on the page, then yes – attaching the event to the table(s) is the better approach. If however you have dozens or hundreds of tables on the page, you’re better off using $(‘document’).delegate(‘table td’) so that only one event is registered on the document node. It’s a balance between preventing unnecessary bubbling and reducing the number of event listeners required.

  • Anonymous

    $(“td”,$(‘table’)).live(“click”, fn);

    should not be (of course it isn’t yet) the same as

    $(“table”).delegate(“td”, “click”, fn);

    ?

    cause in fact, live should register the event on the selector right ?
    and so $(“td”,$(‘table’)) should be different from $(“table td”)

  • Anton

    Be sure not to delegate “submit” on to a div though. The nested form won’t pick it up, in my experience (using 1.4.2 and IE7 and 8)

  • http://twitter.com/germangail German Gail

    Checkout http://api.jquery.com/live/. There it says that to set up an element context, we use the JQuery function’s second argument, and this argument should be a single DOM element. In your example, you are passing a JQuery selector, that could imply a collection.

    That’s why in the first example of this page, it is explained that the call to delegate is equivalent to the each() cycle, using each table taken from the result of the selector, as context for each bind() call.

    Hope this helps, bye!

  • Anonymous

    Does Event Delegation also bring performance improvements? Imagine a list with thousands of items. Each click on a should trigger an action. Is it “cheaper” to delegate the click event from the node to the s than assigning each a click event?

  • fbuchinger

    With delegate it seems that you are trading shorter initialisation time for slightly longer event triggering time (the event has to bubble up to the delegator until it is triggered). However, if you have 100s of child nodes with event listener, it's surely better to work with a delegate on the parent node.

  • Anonymous

    Just a thought: wouldn’t it be better to also support a delegate method that takes a map?
    something like:
    $(“div”).delegate({ click: { span: function(){}, img: function {} },
    hover: { span: function () {}, img: function {} });

    I’d assume it’ll be more performant.

  • http://profiles.yahoo.com/u/7NYQZPD2UFPQYVD2UQ575CHUGY Ryan

    Am I nuts or has the argument order changed in the most recent version?

    The documentation states the order as .delegate( selector, eventType, handler )

    This doesn’t work. But the following does:
    .delegate( eventType, selector, handler )

    I actually know I’m not nuts :) The function in the jQuery source states it as so:
    function( type, delegate, handler ) {}

    Not sure when this was changed but I was a real zinger when I tried waay too many times to make it work.

  • http://www.learningjquery.com/ Karl Swedberg

    Or…maybe you are crazy. ;-)

    Here is the code from the jQuery core file:
    delegate: function( selector, types, data, fn )

  • Michael Robertson

    I’m definitely crazy then!

    In a standalone page I used the syntax .delegate( selector, eventType, handler ) and it worked as expected.

    After refactoring and including the the targets in a tab, that syntax would simply not work. I changed it to .delegate( eventType, selector, handler ) and now it works. That syntax in the standalone page does not work!

    The code fragment involved is $(“#c-order”).delegate(“change”, “input”, function () {…..

    I used EventBug to see what was being bound. When the documented syntax was used the “change” event was not bound for any input element. When the other syntax was used, the “change” event was bound as expected.

    This was in a local environment initially, and after uploading to a development environment on my host I saw exactly the same behaviour.

    Something is not quite right here.

  • http://openid.lerch.org/emil Emil Lerch

    We just ran into this problem on our project and it turned out that the validation plugin was defining the delegate function. It appears this has been fixed in the validation plugin (see http://plugins.jquery.com/node/13455). This may or may not be your problem, but it appears to be ours.

  • Anonymous

    Emil’s post has fixed my issue. The refactoring included adding the validate plugin. One I upgraded to 1.7 and changed the syntax of the delegate method all is well.

  • http://profiles.yahoo.com/u/7NYQZPD2UFPQYVD2UQ575CHUGY Ryan

    No idea where I got that jQuery source from. Just looked again and, of course, you were right Karl. Maybe I did a project-wide search and the validation plugin is what came up.

    And Emil Lerch was right. Updated to the new version of the validation plugin and all is right with the world.

    Thanks for the help guys.

  • http://twitter.com/jethrolarson Jethro Larson

    Why wouldn’t it be:
    $(“div”).delegate(“li”,{
    “click”:function(){},
    “hover”:function(){}
    });
    ?

  • http://twitter.com/jethrolarson Jethro Larson

    Why wouldn’t it be:
    $(“div”).delegate(“li”,{
    “click”:function(){},
    “hover”:function(){}
    });
    ?

  • garukun

    The thought process I took was that the event handler was attached to the parent element “div” and was not actually attached to the “li” or “span” inside it. I think it loggically makes sense to do that your way, but it maybe more performant code-wise to delegate per event.

  • garukun

    The thought process I took was that the event handler was attached to the parent element “div” and was not actually attached to the “li” or “span” inside it. I think it loggically makes sense to do that your way, but it maybe more performant code-wise to delegate per event.

  • Shelhamer

    The reason for the different terminology is because under the hood event delegation is being used, in that a single event handler is being declared for the element calling delegate() instead of an event handler is not placed on every elemented selected (by the first argument). This scales far better by using event bubbling in javascript. You could read more about it here: http://www.sitepoint.com/blogs/2008/07/23/javas…

  • http://keturn.net/ Kevin Turner

    yes, but live() does that too.

    The most reasonable thing I can think of is “bind and delegate are different things, and forget about that thing we called live because it has a silly name and you should probably use delegate now anyway.”

  • Green

    For input fields that include [ ], the name most not be escaped unlike for bind or for a normal selector.

    $(“input[name='x\[\]']”)
    $(“input”).delegate(“[name='x[]']”, 'change', function)

    See http://jsbin.com/eyoro3/4/edit

  • Gethin Webster

    It's worth noting that not *all* selectors will work as expected within .delegate(): while $('#mydiv').find('>p').bind('click', myFunction) will work, $('#mydiv').delegate('>p', 'click', myFunction) will not.

  • Kassapa

    How do we bind an event hanlder to a future element. i.e. say

    $(“table”).delegate(“td”, “hover”, function(){
    $(this).toggleClass(“hover”);
    });

    this will bind the hover of any current or future td elements of current tables. But does this binds the event to any td in a future table as well?

  • Gethin Webster

    There’s no way of exactly replicating that, but as td elements have to be in a table you could delegate on something further up the chain, ie:

    $(‘body’).delegate(‘td’, ‘hover’,…)

    Or, if you only want to delegate to td elements in tables with a certain class:

    $(‘body’).delegate(‘table.myClass td’, ‘hover’,…)

  • Kassapa

    yes. delegating the event to the body would do the the work. But it would be nice if it is possible to delegate it to a future element as well; but I’m in doubt if it is possible.

  • http://codemonkeybryan.com Bryan Elliott

    From a performance standpoint, it's kind of trivial to flip an object (i.e., O(xy) for a nominally small x and y), so it's probably best to go with what's logical from the library consumer's point of view – i.e., obj[selector][event], and let the library mangle the input however it needs to.

  • http://codemonkeybryan.com Bryan Elliott

    You’re also gaining a certain amount of error avoidance with the live-like functionality that delegate brings (i.e., futzing with the DOM doesn’t leave your carefully crafted behaviors dead), but without every event bubbling all the way back to the documentElement. It’s kind of a performant trade-off for scripts that will have some idea of the document structure (i.e., anything site- or tool-specific).

  • http://twitter.com/MarcusKabele Marcus Kabele

    FYI: take care when you want to delegate .hover() == .mouseenter().mouseleave()

    You have to use the (problematic) “mouseover mouseout” events:
    .delegate(“.hover”,”mouseover mouseout”, function(event) {
    if (event.type == 'mouseover') { …

    .delegate(“.hover”,”mouseenter mouseleave”, … is not supported by standard browsers.
    jQuery emulates these proprietary events in .mouseenter() and .mouseleave(), but they are not fired as events in modern browsers (and jQuery 1.4.2).

    .delegate(“.hover”, “hover”, … only provides the single-function toggle functionality.

    The same is true for .live()

  • http://www.learningjquery.com/ Karl Swedberg

    You might want to look into the livequery plugin. It doesn't delegate to future elements, but it does bind to them:

    http://github.com/brandonaaron/livequery

  • Wilsonmacariano

    Hey Marcus! Thank you very much for the tip! I have been looking for this solution sometime ago and i just could not find it! Thank you! =]

  • Sid_M

    Try jQuery('#mydiv').delegate('#mydiv > p', 'click', function() {
    console.log(this.innerHTML);
    });

  • http://www.chicagoworks.com chicagoworks

    Try this… it overrides delegate(), if ‘selector’ is an object it loops over the object and calls .live()
    for each item, otherwise it calls .live() just like the original .delegate(). It’s roughly similar to the
    way the map is implemented in .bind().

    //OVERRIDE DELEGATE
    (function($) {
    $.fn.delegate = function(selector, types, data, fn) {
    if (typeof selector === “object”) {
    for (var sel in selector) {
    for (var type in selector[sel]) {
    this.live(type, data, selector[sel][type], sel);
    }
    }
    return this;
    } else {
    return this.live(types, data, fn, selector);
    }
    };
    })(jQuery);

    //SAMPLE USAGE
    //call delegate with an object map of selectors, events and function
    //NOTE: data object is the second parameter
    $(‘#header’).delegate({
    ‘img’ : {
    ‘click dblclick’:function(){
    console.log(‘clicked’)
    }
    },
    ‘li’ : {
    mouseover:function(){
    console.log(‘over’)
    },
    mouseout:function(){
    console.log(‘out’)
    }
    }
    }, {foo:123 , bar:456});

    //test regular delegate call
    $(‘#header’).delegate(‘img’, ‘click dblclick’, function click(){
    console.log(‘clicked’)
    });

    //test regular delegate call with a data object
    $(‘#header’).delegate(‘img’, ‘click dblclick’, {foo:123 , bar:456}, function click(){
    console.log(‘clicked’)
    });

  • http://twitter.com/plesin Radek Pleskac

    Hi,

    is there a way to delegate multiple events of the same type, and all of them are gonna work?
    When I lets say bind multiple clicks to an element, all of the clicks trigger, but when I delegate multiple clicks for an element only the first one is triggered.

    When I look at the events bound in fireQuery, I can se the events are bound to the element, but all of them won't fire, just the first one.

    Thanks Radek

  • Crunksounds