Paul Irish

Making the www great

Markup-based Unobtrusive Comprehensive DOM-ready Execution

2012.02.07: Looking back at this very awkward name is.. awkward. This technique is called routing and is available in Rails, Django, Sammy.js, LeviRoutes and Backbone. I’d essentially rename this technique DOM-based Routing, with the catch that it’s for page refresh situations and not single page apps.

On a recent project I took my previous approach to automating firing of onload events to a new level.

For instance if your code was architected in an object literal such as:

1
2
3
4
5
6
7
8
9
10
11
FOO = {
  common : {
    init     : function(){ ... },
    finalize : function(){ ... }
  },
  shopping : {
    init     : function(){ ... },
    cart     : function(){ ... },
    category : function(){ ... }
  }
}

A page with this body tag:

1
<body id="cart" class="shopping">

would load these functions sequentially:

UTIL.fire is calling: FOO.common.init()
UTIL.fire is calling: FOO.shopping.init()
UTIL.fire is calling: FOO.shopping.cart()
UTIL.fire is calling: FOO.common.finalize()

In addition, using these classes and IDs on the body tag provides some excellent specific hooks for your CSS.

The javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
UTIL = {

  fire : function(func,funcname, args){

    var namespace = FOO;  // indicate your obj literal namespace here

    funcname = (funcname === undefined) ? 'init' : funcname;
    if (func !== '' && namespace[func] && typeof namespace[func][funcname] == 'function'){
      namespace[func][funcname](args);
    }

  },

  loadEvents : function(){

    var bodyId = document.body.id;

    // hit up common first.
    UTIL.fire('common');

    // do all the classes too.
    $.each(document.body.className.split(/\s+/),function(i,classnm){
      UTIL.fire(classnm);
      UTIL.fire(classnm,bodyId);
    });

    UTIL.fire('common','finalize');

  }

};

// kick it all off here 
$(document).ready(UTIL.loadEvents);

This system worked very well and keeps you in serious control of the execution order.

In the end, I used this plus a custom event to bind super low priority script. For example:

1
$(document).bind('finalized',function(){ ... }); // placed within a FOO.shopping.category()

And I’d trigger that

1
$(document).trigger('finalized');

at the very end of UTIL.loadEvents(). This allows you to keep similar code together, but delay portions responsibly without any setTimeout ugliness.

2010.10.28: OMG this shit just got next level….

So Blake Waters presented this topic in August this year.

And now Jason has published his approach on the most excellent Viget Inspire blog. Please check it out.

It’s essentially using data-attributes instead of classes to trigger this action.. So..

1
<body data-controller="users" data-action="show">

Will fire off:

FOO.common.init();
FOO.users.init();
FOO.users.show();

Boom boom bam. I dig it. Check it out in its full glory.

Comments