Event Pooling with jQuery Using Bind and Trigger: Managing Complex Javascript
Dec 5 2008Managing 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.
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.
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.
[]5