Poor man’s JavaScript Behaviours

JavaScript behaviours are roughly defined as an event handler that is set once, then handled by elements that are created on the fly later on.

For example, if I have a list of links referencing images which are loaded inline, adding an removing the links from this list would not require me to re-hook the event handler.

There is a jQuery plugin called LiveQuery which can handle this for you, and does so by caching the event handler you set and hooking in to the .append(), .after(), etc, methods to reattach the cached event handler to the newly created elements.

The poor man’s behaviours takes a different approach.

The technique is really very simple, and if you’ve been writing JavaScript you may have already made use of it in some form. It doesn’t use a timer, and makes use of event bubbling.

In our example, our HTML would look like this:

<ul id="imageLinks">
  <li><a href="/images/1.jpg">Image 1</a></li>
  <li><a href="/images/2.jpg">Image 2</a></li>
  <li><a href="/images/3.jpg">Image 3</a></li>
</ul>

Clicking on a link would load the image dynamically, but for our example, we’ll just log the image url.

The JavaScript event handling is set on the ul element instead of the anchor elements.

// addEvent function for IE + Firefox
var addEvent = (function () {
  return document.body.addEventListener ? function (e, ev, fn) {
    e.addEventListener(ev, fn, false);
  } : function () {
    e.attachEvent("on" + ev, fn);
  };
})();

addEvent(document.getElementById('imageLinks'), 'click', function (event) {
  // only proceed if the user click on an anchor
  var el = event.target;
  if (el.nodeName == 'A') {
    // this is our real event code - which we can read values
    // from the 'el' variable, including .href, .rel, etc. to
    // handle specific like code
    console.log(el.href);
    return false; // cancel click event
  }
});

As you can see the core of the event handling is within the if (el.nodeName == 'A') (note the casing on the nodeName must be capitalised). If you need to match a class name, you can do it here too.

Taking it Further

This can be converted to a jQuery plugin, that supports more complicated selector matches, again without any timeouts.

It’s limitation over LiveQuery, is that it’s restricted to a subset of elements, i.e. a group of links that match X selector within a UL.

(function ($) {
  $.fn.behaviour = function (selector, fn) {
    return this.click(function (ev) {
      var el = ev.target;
      if ($(el).is(selector)) {
        return fn.call(el);
      }
    });
  };
})(jQuery);

$(function () {
  $('#imageLinks').behaviour('a', function () {
    console.log('Clicked link: ' + this.href);
    return false;
  });
});

Here’s a working demonstration of poor man’s behaviours

9 Responses to “Poor man’s JavaScript Behaviours”

  1. Just a simple correction. Live Query doesn’t rely on timers to monitor the DOM. Instead it uses hooks.

  2. @Brandon – cheers for the correction. I’ve updated the blog post.

  3. Nice! I’ve been looking for a bubbling-events-example written in jQuery. Very handy indeed.

  4. Hi Remy
    What you are showing, already exists as a plugin, actually twice.
    Intercept:http://code.google.com/p/jqueryintercept
    Delegate:http://dev.jquery.com/browser/trunk/plugins/delegate/jquery.delegate.js

    Listen is similar but not exactly the same.
    Listen:http://flesler.blogspot.com/2007/10/jquerylisten.html

    Cheers

  5. @Ariel, I’d agree with you on the delegate plugin (the first link doesn’t work), but the plugin I wrote above is just supposed to be very simple.

    Really, I posted to demonstrate the simplistic behaviour approach, and I show this using “vanilla JS” first.

    Personally, if I were to use behaviours extensively on an app, I’d be more inclined to use Brandon’s liveQuery plugin.

  6. Hi Remy
    I meant my post as informative, not attacking, really :)
    The link was meant to be:
    http://plugins.jquery.com/project/Intercept

    Anyway, that plugin it’s pretty outdated. Note that LiveQuery belong to Brandon, not Jorn.

    And I agree LiveQuery is the easiest to implement. But event delegation also has its advantages on large apps.

  7. @Ariel – no problem! :-)

    Thanks for the correction too – I’ll update that now.

  8. [...] Poor man’s JavaScript Behaviours [...]

  9. There’s an error in the IE half of the addEvent function. It should look like this:

    var addEvent = (function () {
    return document.body.addEventListener ? function (e, ev, fn) {
    e.addEventListener(ev, fn, false);
    } : function (e, ev, fn) { // this line was incorrect
    e.attachEvent(“on” + ev, fn);
    };
    })();

    Thanks for making this code available!

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight