Dugan Chen's Homepage

Various Things

Javascript MVC View Dispatcher

I probably shouldn’t start blogging even before my website migration is done, but I need to mention this. I’ve recreated Django’s URL dispatching subsystem in Javascript. My version, appropriately, responds to changes in the URL hash and not in the whole URL.

The way it works is that you have a list of pairs of regular expression patterns and controller functions. Every time the hash changes, the system iterates through the pairs. For each pair, it checks if the hash matches the pattern. If so, then it calls the controller function and stops.

To extract data from the patterns to pass to the controller functions, just put capturing parentheses in the patterns.

First, put the following goes in a framework-independent file called urlconf.js. It creates a createHashHandler factory function, which takes a list of pattern-controller pairs and returns a function to respond to hash changes.

var createHashHandler = function (urlPatterns) {
    var patterns = urlPatterns;
    return function (event) {
        // We assume that the window.onhashchange event exists.
        var index = window.location.hash.indexOf('#'),
            length = window.location.hash.length,
            fragment, // just the URL fragment value.
            result, // regex comparision result.
            i;

        if (index > -1 && index + 1 < length) {
            for (i = 0; i < patterns.length; i += 1) {
                fragment = window.location.hash.slice(index + 1);
                result = patterns[i].re.exec(fragment);
                if (patterns[i].re.exec(fragment) !== null) {
                    patterns[i].view.apply(this, result.slice(1));
                    break;
                }
            }
        }
    };
};

Once you’ve called the factory function to create your handler, you can do two things. First, you can bind it to the onhashchange event to listen for future hash changes. Second, you can call it directly, to respond to the current url hash. Here’s an example that uses jQuery:

/*global $, createHashHandler */

var handleDigits = function (d) {
    alert(d);
};

var handleWordChars = function (w) {
    alert(w);
};

$(function () {
    var handleHashChange = createHashHandler([{
        re: /(\d+)/,
        controller: handleDigits
    }, {
        re: /(\w+)/,
        controller: handleWordChars
    }]);

    $(window).bind('hashchange', handleHashChange);
    handleHashChange();
});

Presto. Your application is now listening for hash changes. Every time the hash changes to one that it recognizes, it will extract the appropriate data from the URL hash, then call the appropriate function with the data as the parameter(s). It works with bookmarks too.