The event-extensible JavaScript (jQuery) pattern

Tags: pattern, jQuery, JavaScript, events, Orchard, extensibility

In JavaScript we can employ the same basic principle mentioned earlier at the end of the dynamic page pattern post. That means, events (in the previous post: Orchard events, here: jQuery events and event handlers) are a great tool when you want to provide some dynamically, independently extensible frame for others to hook into. The framework just calls into the event methods, and "listening" codes simply get the message, without some explicit registration or upfront configuration. Today we'll see how easy it is to write extensible JavaScript code with jQuery events. (I'll make reference to the Orchard resource handling mechanism, but the principle is usable outsides Orchard too.)

Let's assume you have a "framework" script and another script that extends it. You could also have multiple scripts that extend the framework.

The framework:

(function ($) {
    $(function () { // This is the same as $(document).ready()
        var messages = {
            firstHello: "Hello computer!",
            secondHello: "Hello me!"
        };

        $(document).triggerHandler({
            type: "composeMessage.HelloFramework",
            messages: messages
        });

        alert(messages.firstHello);
        alert(messages.secondHello);
    });
})(jQuery);

This incredibly simple script runs the message strings through the "composeMessage.HelloFramework" event handler. That means, any code hooking into this event handler will be able to modify the messages.

Notice the fancy lambda around the whole code block. Why it matters is well explained on the jQuery HowTo blog.

And now the event handling script:

(function ($) {
    $(document).on("composeMessage.HelloFramework", function (values) {
        values.messages.firstHello = "Hello world!";
        values.messages.secondHello = "Hello you!";
    });
})(jQuery);

Now this event handler modifies the messages, so in the end "Hello world!" and "Hello you!" is displayed.

There are a several things to note here:

  • Notice that I wrapped the messages in a closure, so they're inside an object. Much like in C#, objects in JS are automatically passed by reference (unlike value types like strings), so the event handler can modify the original strings.
  • You can pass an arbitrary number of arguments ("values") to event handlers. I happen to only use one here (messages), but you could continue to list other fields too in the triggerHandler call.
  • The type field is reserved when calling triggerHandler; that's the name of the event.
  • I tried the code in this order: the event triggering code comes first and the event handler second. Because of jQuery's ready method however, still, all the code is parsed, all the event handlers are detected before the event is triggered.
  • Because of the previous point, this technique plays along well with Orchard's resource handling. The framework could be in a separate script, having a resource entry and you can make your second script's resource entry depend on the framework's. This way the event handler will be included after the framework, what is pretty much indifferent here. However if you use anything in the event handler from the framework (e.g. the framework contains some common methods) this is the desired effect.
  • As mentioned earlier, there can be an arbitrary number of event handlers for the same event, the input will be passed through all of them.

I hope this showed how powerful this technique could be; I use it in a few projects with great joy :-).

Happy event handling!

No Comments

Add a Comment