Event Pooling with jQuery Using Bind and Trigger: Managing Complex Javascript

Managing Complexity in the UI

As everyone knows, the more dependencies you have in a system, the harder maintaining that system is.  Javascript is no exception- and orchestrating actions across complex user interfaces can be a nightmare if not done properly.

Luckily, there’s a great pattern for orchestrating complex interaction in a disconnected way. No, it’s not the Observer pattern.  It’s a take on the Observer pattern called Event Pooling which is a piece of cake with jQuery’s bind and trigger functions.  For the get to the code folks, here’s an example of using jQuery’s bind and trigger for event pooling.

Problems with the Observer Pattern

The observer pattern is great for some things, but it still requires a dependency between the observer and the subject.  The publish/subscribe scenario creates a direct relationship between two objects- and makes orchestrating a lot of events difficult when you have to manage so many direct references.

observer pattern

observer pattern

Event Pooling

Event pooling is simply a variation on the Observer pattern, where a “middle man” is used to orchestrate the publish/subscribe system.  First, an observer will register with the event pool by saying “I need to call this function when this event is fired”.  Next, the subject will tell the event pool “I’m firing this event”.  Finally, the event pool will call the function the observer registered on behalf of the subject.  The observer and subject only need to know about the event pool, not each other.

Event Pool

Event Pool

This provides some cool functionality- especially because if you need to reference the subject (called the publisher), you can get a direct reference via the event pool.  This is similar to the object sender parameter in .NET’s event system.

Show me Code!

We are going to do two things: First, update a span tag to show an address when a user enters a name, city, or state.  Second, show some complex behavior by daisy changing events and binding a single function to multiple triggers. Check out the example.

We have an UpdateOutput() function that updates the span:

function UpdateOutput() {
    var name = $('#txtName').val();
    var address = $('#txtAddress').val();
    var city = $('#txtCity').val();

    $('#output').html(name + ' ' + address + ' ' + city);
}

This is wired up via the bind function:

$(document).bind('NAME_CHANGE ADDRESS_CHANGE CITY_CHANGE', function() {
    UpdateOutput();
});

Notice how we’re wiring up multiple event names with a single function which calls UpdateOutput.  This allows us to encapsulate common functionality in a single function which could be called from various sources.

We’re also binding and firing to $(document).  Document provides a global bucket all functionality has access to- a static class that can be referenced from anywhere, making pooling easy.

We can also wire up another function with the NAME_CHANGE event without effecting any other logic:

$(document).bind('NAME_CHANGE', function(e) {
    UpdateName();
    UpdateOtherText(e);
});

Here, NAME_CHANGE will also trigger UpdateName and UpdateOther.

Firing an event is done with the trigger function:

$('#txtAddress').keyup(function() {
    $(document).trigger('ADDRESS_CHANGE');
});
$('#txtCity').keyup(function() {
    $(document).trigger('CITY_CHANGE');
});

It can also be called directly from html:

Name: <input type="text" id="txtName" onkeyup="javascript:$(document).trigger('NAME_CHANGE');" />

Advanced Functionality

There are two more things you can do with bind and trigger: Inspect who fired the trigger (this can be important if you’re wiring up a single function from multiple subjects) and pass data to the event.

In our next example, our function definition takes in two parameters: e, which is the event’s sender, and data, a generic data bucket:

$(document).bind('FIRST_UPDATED', function(e, data) {
    UpdateOtherText(e, data);
});

The first parameter will always be the event’s sender.  You can wire up as many other parameters as you want.  You pass data as a comma delimited list between brackets [parm1,parm2] when calling trigger:

$(document).trigger('FIRST_UPDATED', [data]);

and from html:

<input type="text" id="txtData" onkeyup="javascript:$(document).trigger('DATA_CHANGED', [$(this).val()]);" />

The sender object has a couple of properties, but the most important is ‘type’, which let’s you know what triggered the event:

function UpdateOtherText(e, text) {
var text;
if (e.type == 'FIRST_UPDATED')
 text = 'from first: ' + text;
else
 text = e.type;
$('#eventFired').html(text);
}

Check out my follow up article Organizing Events for Event Pooling.


kick it on DotNetKicks.com

  • http://www.omsn.de korbsan

    good article, thanks

  • http://www.subprint.com Joseph McCann

    Awesome, AWESOME article. Very succinct and informative. Will put into practice right away.

    Question, how does this play into solid jQuery event delegation, say for elements added to the DOM on the fly, via AJAX or another method? Can this concept be taken a step further to include event delegation?

  • http://www.michaelhamrah.com Michael

    Hey Joseph- great question. The example above uses standard jQuery event handling to fire a trigger. As you point out, jQuery won’t hook up these events when elements are added dynamically- which is why you need event delegation.

    I find the livequery plugin a great tool for ensuring dynamically added elements are wired correctly.

    I still like the level of abstraction explicitly firing a trigger brings to the table. This allows two great benefits: multiple triggers can be fired in a single event and data can be processed or prepared before being passed to the trigger. This allows the same binding to handle events in a uniform way from a variety of sources.

    Of course, there’s a couple of ways to skin a cat- so I’m sure you can fire triggers via some event delegation system. But I find the combo of livequery and event pooling pretty slick for solving a lot of problems!

  • Pingback: jQuery Event Pooling | MirthLab

  • http://www.simplewebapp.com mindreframer

    I think this pattern is called Message Bus on Client Side. Check this URL:

    - http://www.adamzastawski.com/post/Ride-the-Page-Bus-(TIBCO-PageBustrade3b).aspx

    Dojo is fundamentally based on this approach, BTW.
    Cheers, Roman

  • http://www.subprint.com Joe McCann

    Nice Michael…yes, I have used livequery in the past, but have been trying to be more of a purist with event delegation so I figured I’d ask.

  • Pingback: Interesting Finds: 2008.12.08~2008.12.11 - gOODiDEA.NET

  • http://webdevvote.com webdevvote
  • http://www.thexvid.com/video/11020/comedy-club-ukraine-24-РґСѓСЌС‚-имени-чехова Den Flatieneiream

    Very usefull post.
    Thanks.
    P.S. I like your writing style.

  • http://www.thexvid.com/articles/8906/coffee-cupping-for-the-fun-of-it Tom Flatieneiream

    First of all congratulation for such a great site. I learned a lot reading article here today. I will make sure i visit this site once a day so i can learn more.

  • http://www.dreinavarro.com/blog Andrei Navarro

    Awesome article.

    I’ve always ran into situations where I need multiple events triggering a common functionality.

  • http://blogs.claritycon.com/blogs/sean_devlin/default.aspx Sean Devlin

    Michael,

    Great article. I did something similar recently for a project at work. My solution was homebrewed, since I didn’t know about jQuery’s support for custom events at the time. You can check out my solution here.

    There are two things I like better about my solution. One is that it’s not tied to the DOM (the document, in your example), since I don’t think that makes sense for a “business logic” event. Two is a more natural interface for passing event arguments.

    One notable feature you call out for jQuery’s solution that I don’t see a simple way to add to mine is the optional reference to the caller.

    Anyway, if you get a chance to check it out, I’d love to hear your thoughts.

    Sean

  • Pingback: Event Pooling with jQuery Using Bind and Trigger: Managing Complex Javascript | Adventures in HttpContext « Netcrema - creme de la social news via digg + delicious + stumpleupon + reddit

  • Pingback: The Technology Post for July 6th, 2009 | I love .NET!

  • Mo

    Thanks for your work. Very understandable theoretically.

    But why don’t you write a workable code for the examples.

    I have no idea to handle these events like “NAME_CHANGE”, “ADDRESS_CHANGE”, “CITY_CHANGE” because they are not the standard events.

    Looking forward to your further explanation.

  • Pingback: The Technology Post for July 6th, 2009 | Nexo IT - Information Technology News

  • http://www.pixeline.be Alexandre Plennevaux

    @Mo: that’s the whole point, you know, “custom events”. You need to shift your perspective around embracing the pattern described in this post.

    Michael, i would like to know if you experimented this logic with the live(); binder, which pretty much does what livequery did and is integrated in the core since 1.3.0 . (I noticed your example uses 1.2.6).

    I’ll try to experiment it on my own but i ‘m in a tight schedule about refactoring a big jquery-based application, and your pattern seems really interesting. But my application uses livequery extensively, hence my question.

    Thanks for the great article!

    Alexandre

  • Pingback: Event Pooling with WordPress | scribu

  • http://www.2meter3.de/code/hoverFlow/ Ralf Stoltze

    While using inline event handlers is just considered bad practise, using the javascript: pseudo protocol within inline event handlers is simply wrong.

    Otherwise, good article!

  • http://www.michaelhamrah.com Michael

    Hey Ralf- you’re absolutely correct. Unobtrusive javascript is the way to go. There are three main benefits: all your js hook ups are in one place, it’s in an external file so it reduces the download size of the html page, and it keeps the html semantically correct. This is helpful when porting your html code to different browsers or devices.

    Jeff Atwood has written about the dangerous of blindly copying and pasting code from the internet- I was just making the examples easier to write!

  • http://www.michaelhamrah.com Michael

    @Alexandre- I wrote this article before the introduction of live() and die(). I know there are subtle yet important differences between live() and livequery- it’s worth checking it out further. Maybe a topic for another article.

  • Pingback: lillbra » Blog Archive » links for 2009-07-30

  • Pingback: BenjaminBoyle.com » Blog Archive » Great jQuery event handling articles

  • Pingback: Organizing Events for Event Pooling with jQuery | Adventures in HttpContext

  • Pingback: 9eFish

  • Pingback: Custom events and event pooling in jQuery – What’s the point? | Webmaster Forum Archive

  • http://zygorguidesreview.wikispaces.com Zygor’s Guide

    I read this just a few minutes ago and thought I’d pass it along although it’s not genuinely that relevant. For those who could relive yesterday what would you do differently?

  • http://www.name623.com Name623
  • http://www.name624.com Name624

    Thank you for this great article. Using jQuery trigger I’ve created an Observer Pattern Example, which is really useful in front-end development.
    I also recommend reading these articles:
    Page Visibility
    Network Information API
    Contacts API

  • eliseo abadia

    muchas gracias , me ayudó mucho su pagina… gracias.

  • http://maty.us Michael Matyus

    Been trying to understand binding and triggering. The article has given me some good background, unfortunately, http://www.michaelhamrah.com/blog/wp-content/uploads/jqueryEventPool/index.html is throwing a 404 :( Help!

  • http://www.michaelhamrah.com Michael

    @Michael Matyus: the link is fixed. Sorry about that!

  • Pingback: Change ‘this’ when firing custom events in jQuery using $.trigger()

  • Pingback: Eigene Events mit jQuery Bind und Trigger › Der Blog von Benny Neugebauer

  • Pingback: NodeJS Installation | Blog of Π

  • Caleb Gilbert

    For what it’s worth, what this article describes is called the mediator pattern. More compare and contrast here: