Non-Dom Element Event Binding with jQuery

Posted on Dot net Slackers See other posts from Dot net Slackers
Published on Thu, 27 May 2010 00:00:00 GMT Indexed on 2010/05/27 23:42 UTC
Read the original article Hit count: 898

Filed under:
Yesterday I had a short discussion with Dave Reed on Twitter regarding setting up fake events on objects that are hookable. jQuery makes it real easy to bind events on DOM elements and with a little bit of extra work (that I didnt know about) you can also set up binding to non-DOM element event bindings. Assume for a second that you have a simple JavaScript object like this: var item = { sku: "wwhelp" , foo: function() { alert('orginal foo function'); } }; and...

Did you know that DotNetSlackers also publishes .net articles written by top known .net Authors? We already have over 80 articles in several categories including Silverlight. Take a look: here.



Email this Article

© Dot net Slackers or respective owner

Non-Dom Element Event Binding with jQuery

Posted by Rick Strahl on West-Wind See other posts from West-Wind or by Rick Strahl
Published on Thu, 27 May 2010 23:14:51 GMT Indexed on 2010/05/27 23:22 UTC
Read the original article Hit count: 898

Filed under:

Yesterday I had a short discussion with Dave Reed on Twitter regarding setting up fake ‘events’ on objects that are hookable. jQuery makes it real easy to bind events on DOM elements and with a little bit of extra work (that I didn’t know about) you can also set up binding to non-DOM element ‘event’ bindings.

Assume for a second that you have a simple JavaScript object like this:

var item = { sku: "wwhelp" , 
             foo: function() { alert('orginal foo function'); }              
};

and you want to be notified when the foo function is called.

You can use jQuery to bind the handler like this:

$(item).bind("foo", function () { alert('foo Hook called'); } );

Binding alone won’t actually cause the handler to be triggered so when you call:

item.foo();

you only get the ‘original’ message. In order to fire both the original handler and the bound event hook you have to use the .trigger() function:

$(item).trigger("foo");

Now if you do the following complete sequence:

var item = { sku: "wwhelp" , 
             foo: function() { alert('orginal foo function'); }              
};
$(item).bind("foo", function () { alert('foo hook called'); } );
$(item).trigger("foo");


You’ll see the ‘hook’ message first followed by the ‘original’ message fired in succession. In other words, using this mechanism you can hook standard object functions and chain events to them in a way similar to the way you can do with DOM elements. The main difference is that the ‘event’ has to be explicitly triggered in order for this to happen rather than just calling the method directly.

.trigger() relies on some internal logic that checks for event bindings on the object (attached via an expando property) which .trigger() searches for in its bound event list. Once the ‘event’ is found it’s called prior to execution of the original function.

This is pretty useful as it allows you to create standard JavaScript objects that can act as event handlers and are effectively hookable without having to explicitly override event definitions with JavaScript function handlers. You get all the benefits of jQuery’s event methods including the ability to hook up multiple events to the same handler function and the ability to uniquely identify each specific event instance with post fix string names (ie. .bind("MyEvent.MyName") and .unbind("MyEvent.MyName") to bind MyEvent).

Watch out for an .unbind() Bug

Note that there appears to be a bug with .unbind() in jQuery that doesn’t reliably unbind an event and results in a elem.removeEventListener is not a function error. The following code demonstrates:

var item = { sku: "wwhelp",
    foo: function () { alert('orginal foo function'); }
};
$(item).bind("foo.first", function () { alert('foo hook called'); });
$(item).bind("foo.second", function () { alert('foo hook2 called'); });

$(item).trigger("foo");


setTimeout(function () {
    $(item).unbind("foo");
    // $(item).unbind("foo.first");
    //  $(item).unbind("foo.second");

    $(item).trigger("foo");
}, 3000);

The setTimeout call delays the unbinding and is supposed to remove the event binding on the foo function. It fails both with the foo only value (both if assigned only as “foo” or “foo.first/second” as well as when removing both of the postfixed event handlers explicitly. Oddly the following that removes only one of the two handlers works:

setTimeout(function () {
    //$(item).unbind("foo");
    $(item).unbind("foo.first");
    //  $(item).unbind("foo.second");

    $(item).trigger("foo");
}, 3000);

this actually works which is weird as the code in unbind tries to unbind using a DOM method that doesn’t exist. <shrug>

A partial workaround for unbinding all ‘foo’ events is the following:

setTimeout(function () {
    $.event.special.foo = { teardown: function () { alert('teardown'); return true; } };
    $(item).unbind("foo");

    $(item).trigger("foo");
}, 3000);

which is a bit cryptic to say the least but it seems to work more reliably.

I can’t take credit for any of this – thanks to Dave Reed and Damien Edwards who pointed out some of these behaviors. I didn’t find any good descriptions of the process so thought it’d be good to write it down here. Hope some of you find this helpful.

© Rick Strahl, West Wind Technologies, 2005-2010
Posted in jQuery  
kick it on DotNetKicks.com

© West-Wind or respective owner

Related posts about jQuery