Copy Events from One Element to Another

read 3 comments

Need to clone an element and its events? Sure, you could rebind the events after doing the clone, but that wouldn't be very DRY now, would it? Introducing Copy Events, a new plugin for jQuery.

Clone an Element and its Events

The Copy Event plugin makes it easy to clone an element and its events. How? Amazingly simple. Let's say you have an unordered list and each list item has a click, mouseover, and mouseout event. Now you need to clone the last list item and append it to the unordered list.

Here is the HTML:

HTML:
  1. <ul id="myList">
  2.     <li>List Item 1</li>
  3.     <li>List Item 2</li>
  4.     <li>List Item 3</li>
  5. </ul>

Here is the JavaScript that applies the event handlers during the $(document).ready event:

JavaScript:
  1. $('#myList li')
  2.     .bind('click', function() {
  3.         alert( $(this).text() );
  4.     })
  5.     .bind('mouseover', function() {
  6.         $(this).addClass('over');
  7.     })
  8.     .bind('mouseout', function() {
  9.         $(this).removeClass('over');
  10.     });

Now, here is the code to clone the last list item with its events:

JavaScript:
  1. $('#myList li:last')
  2.     .cloneWithEvents()
  3.     .text('List Item ' + ($('#myList li').size()+1))
  4.     .appendTo('#myList');

DONE! Simple as calling cloneWithEvents(). This method takes an optional parameter called "deep" — just like the clone() method — which, if set to false, copies only the element itself, without any of its descendants. You can see the results here.

More Than Just Cloning

The Copy Events plugin offers two more methods to allow for easy copying of events from one element to another or to several other elements. The first is the copyEvents() method and copies events from an element to the elements in the jQuery object. The second is the copyEventsTo() method which copies events from the first matched element in the jQuery object to the matched elements passed in. Let's take a closer look at both of these methods using the unordered list as an example again.

The copyEvents() Method

The copyEvents() method will copy all event handlers from a given element to the set of elements in the current jQuery object. What does that mean? Using the unordered list example, let's add some list items to the unordered list using AJAX.

Here is the code for the AJAX call that gets the extra list items, copies the events and adds the items to the list:

JavaScript:
  1. $.get('list-items.html', function(lis) {
  2.     $(lis)
  3.         .copyEvents('#myList li')
  4.         .appendTo('#myList');
  5. });

Notice I passed a selector to the copyEvents() method. This method can take a jQuery object, a DOM Element and/or a selector string. When passing in a jQuery object or selector, it will use the first element to copy events from.

You can see the results for this copyEvents example here.

The copyEventsTo() Method

The copyEventsTo() method acts similar to the appendTo() method. It copies events from the first element in the current jQuery object to the passed in elements. Just like the copyEvents() method, the copyEventsTo() method can also take a jQuery object, a DOM Element and/or a selector string.

Let's say we have a new unordered list and would like to copy the events from the existing list to the new list when clicking on a special link:

HTML:
  1. <a href="#" id="copier" title="Copy Events">Copy Events</a>
  2. <ul id="newList">
  3.     <li>New List Item 1</li>
  4.     <li>New List Item 2</li>
  5.     <li>New List Item 3</li>
  6. </ul>

Now let's look at the JavaScript to copy these events over to the new list:

JavaScript:
  1. $('#copier')
  2.     .one('click', function() {
  3.         $('#myList li')
  4.             .copyEventsTo('#newList li');
  5.         $(this).remove();
  6.         return false;
  7.     });

I've used the one method to bind the click only once to the <a> tag. When clicked, the events will be copied from the first list item in the #myList unordered list.

Check out the example for yourself here.

Next Steps

The Copy Events plugin can be found in the jQuery Plugins SVN repository.

Update

The ability to copy events has been added to jQuery core as of jQuery 1.2.x. Simply use .clone(true).

comment feed

3 comments

  1. Diego Figueira

    The cloneWithEvents is not recursive, is it? I think it would be much more useful if it would copy all the events from current element *and* from all its descendants. For example if you have an event associated to a 'TR' and you have an event associated to a 'A HREF' that is inside that row, 'cloneWithEvents' will only copy the events from the row, but not from the 'A HREF'...

    Thanks,

    Diego

  2. Brandon Aaron

    I agree it does make more sense to make it recursive. I'll put it on my TODO list. :) Thanks for the suggestion.

  3. Jon z

    Pretty badass.. I wonder though, (with > jquery-1.3) if it wouldn't be easier to bind all those events with .live() and then simply clone.

2 Pings

  1. [...] Ya trabajas con jQuery y dominas el arte de clonar elementos. Pero, cielos, un elemento clonado no conserva los manejadores de eventos asignados al original. Brandon Aaron nos presenta su solución en Copy Events from One Element to Another, publicado en Learning jQuery. [...]

  2. [...] Copy Events from One Element to Another » Learning jQuery - Tips, Techniques, Tutorials (tags: development web tips javascript plugin jquery) [...]

Sorry, but comments for this entry are now closed.