Thoughts on Element Delegation

Wednesday, December 24th, 2008 @ 3:54 pm | filed under: Code Releases

Yesterday I released a bit of code that allowed you to delegate events to their parents. This pattern isn’t a new one in JavaScript, but it wasn’t something natively supported in MooTools in any sort of easy interface. You could do it, but you had to write a lot of it yourself.

My version worked like this:

myElement.delegate(test, event, fn);

Update: I have a new version of delegation posted.

Where test was a selector, an array of elements, or a function that would filter each event. My code, however, didn’t really account for mouseover/out bubbling, custom events (a MooTools convention), or the fact that you need to apply the event when it’s a child of the element you are monitoring. I.e. if you delegate to document.body all the click events on links like so:

$(document.body).delegate('a', 'click', someFunction);

You need to determine if the clicked element (the event target) is not just a match for the selector (here, a link) but also if it matches a child of the selector (a dom element inside a link).

Tom Occhino pointed me to a version of this functionality on github authored by Daniel Steigerwald. Here’s his version. This code was headed into the MooTools code for release probably with version 1.3, but that might still be weeks or months away.

I took Daniel’s code, which was far more robust than my own, and refactored it to incorporate my functionality to allow the test to be a selector, an array, or a function. Then there was a big discussion on IRC regarding the topic. Does it make sense for me to release something that’s basically headed for the MooTools codebase before they do? Does it make sense if my version has a different interface than what ends up in MooTools finally? Does my convention for accepting a selector, array, or function make sense?

The discussion there ranged wildly. Much of it was focused on the interface and remains unresolved. Daniel’s code works like this:

myElement.relayEvent(selector, type, fn);
myElement.relayEvents(selector, {
  type: fn,
  type: fn, etc.
});
myElement.unrelayEvents(selector);

I wasn’t so hot on the method names (I like Element.delegate). But then I thought about just using addEvent:

myElement.addEvent(type, fn); //same as usual
myElement.addEvent(type, fn, selector); //delegates

I ultimately decided against accepting arrays and functions for the test after being convinced by everyone on IRC that the use case for that was spurious and that other solutions are more elegant (like custom selectors).

I still like the addEvent integration. This presents a problem with Element.set though. You can do this in MooTools:

myElement.set({
  events: {
    click: fn1,
    click: fn2, etc
  }
});

In order for this to work with the delegation, you’d need to be able to do this:

myElement.set({
  events: {
     selector1: {
      click: fn1,
      click: fn2, etc
    }
  }
});

But this leads to the slightly ugly combination of the two:

myElement.set({
  events: {
     mouseover: fn1
     selector1: {
      click: fn2,
      click: fn3, etc
    }
  }
});

It’s not exactly un-elegant, but it’s not 100% intuitive.

The other option is to continue with something like Element.relayEvent(s). The only thing I really don’t like about Daniel’s implementation is that I can’t remove events the way I remove events in MooTools. I want to pass the event type and the method I originally defined.

As it stands now, I need to think about it some more and need to discuss it with the dev team more thoroughly.

If you need something that works immediately, you can use Daniel’s code above or you can play around with my refactoring of it that uses addEvent integration. I haven’t tested this version as my time today is a little tight (family obligations and whatnot). I’ll see if I can’t work something out by new years.

As always, I appreciate any feedback and input on my work that I publish. What do you think?

No TweetBacks yet. (Be the first to Tweet this post)

3 Responses to “Thoughts on Element Delegation”

  1. Andreas Köberle Says:

    I came up with a similar solution some month ago. But I miss the check function, so its only works with a css class. So in my eyes you are missing some points. Does your solution works with blur, focus and mouseScroll (cause there are some trouble with this in IE). Does your event bubble by them self, so if your filter is “a” and you have a strong element in the link element will the event be fired?

  2. steida Says:

    to: Andreas Köberle

    1) Focus, blur – not working yet. Wait to next MooTools release, or use fix from QEvent – http://code.google.com/p/qevent/

    2) ’so if your filter is “a” and you have a strong element in the link element will the event be fired?’ Of course! check this example: http://daniel.steigerwald.cz/demos/delegated/default.htm

  3. Event Delegation, take 2 » Clientcide (Formerly CNET's Clientside) Says:

    [...] premature my release was. Mainly, I wasn’t checking element’s children for the match. I posted at length about this and why I had removed my delegation plugin. My code, however, didn’t really account for [...]