jQuery API

.delegate()

.delegate( selector,eventType,handler ) 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 )

    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.

    handlerA function to execute at the time the event is triggered.

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

    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.

    handlerA 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.

Delegate is an alternative to using the .live() method, allowing for each binding of event delegation to specific DOM elements. For example the following delegate code:

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

Is equivalent to the following code written using .live():

$("table").each(function(){
	$("td", this).live("hover", function(){
		$(this).toggleClass("hover");
	});
});

See also the .undelegate() method for a way of removing event handlers added in .delegate().

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

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 always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.

Examples:

Example: Click a paragraph to add another. Note that .delegate() binds the click event 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
  • 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()
  • 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! =]
  • 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.
  • 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...
  • 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.
  • Sid_M
    Try jQuery('#mydiv').delegate('#mydiv > p', 'click', function() {
    console.log(this.innerHTML);
    });
  • 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
  • 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.
  • 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.... This may or may not be your problem, but it appears to be ours.
  • Or...maybe you are crazy. ;-)

    Here is the code from the jQuery core file:
    delegate: function( selector, types, data, fn )
  • 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.
  • 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.

  • MichaelJRobertson
    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.
  • garukun
    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.
  • Why wouldn't it be:
    $("div").delegate("li",{
    "click":function(){},
    "hover":function(){}
    });
    ?
  • 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')
    });
  • 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.
  • 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.