Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

First of all, is there a name for this as a bona-fide design pattern? Currently I've just been referring to it as "unobtrusive javascript". Here is a brief example of what I am talking about:

1.) Use HTML5 data-* attributes to define values that will be used in UX scripts. Something like this:

<input type="date" data-app-calendar="datepicker" />

2.) Use script to initialize the javscript behaviors using these data attributes

(function($) {
    $.app = $.app || {};
    $.app.obtruders = $.app.obtruders || {};
    $.app.obtrude = function(selector) {
        var obtruder, obtruders = $.app.obtruders;
        for (obtruder in obtruders) {
            if (!obtruders.hasOwnProperty(obtruder)) continue;
            if (typeof obtruders[obtruder] === 'function')
                obtruders[obtruder].apply(this, 
                    Array.prototype.slice.call(arguments, 0, 1) || document);
        }
    };

    $.extend($.app.obtruders, {
        calendar: function (selector) {
            $(selector).find('[data-app-calendar=datepicker]').datepicker();
        }
    });

    $(function () {
        $.app.obtrude(document);
    });

})(jQuery);

What you end up with, imo, is presentation markup that is very cleanly separated from behavioral scripts. The above example is simple, but you can extend it to more complex scriptable UX like google maps (I am working on this right now). You can even add new "obtruders" in separate javascript files by extending the $.app.obtruders object literal.

Before we start using this pattern more widely in our app, I wanted to pick brains for opinions and try to get ideas of some potential disadvantages of an approach like this. What do you like about this pattern? What don't you like? Why would you choose not to use it?

share|improve this question
    
Could you ellaborate on why your code is better than just $('[data-app-calendar=datepicker]').datepicker(); ? –  alex Dec 11 '11 at 19:15
    
Say I have a lot of others that do things like initializing google maps, setting focus to a text box, disabling buttons when a form is submitted, etc. I can apply all of these behaviors to all pages with 1 script file. Also, if I load new content via ajax, I only have to call 1 method -- $.app.obtrude('#ajax-load-container'); to apply these behaviors to all newly loaded content. –  danludwig Dec 11 '11 at 19:20
    
Seems a lot of work for little benefit. I don't think there's either significant rewards for users (maybe better performance? Have you measured it?) or for developers (well, once this thing is written I don't think it's going to do much harm, but...). I believe Raynos' approach at least means that only JS that is going to be used will be downloaded by the client- but I'm not sure that's going to be much better (increased latency?). I would write some sample stuff using your technique and using plain jQuery. Try objectively to enumerate the pros and cons of each approach and decide. –  alex Dec 12 '11 at 9:44
    
I think the term "unobstrusive Javascript" was originally more for when your page can also work fine without Javascript (due to using an old browser or having it disabled). I don't know if it still as relevant now given how most people now use Javascript compatible browsers. –  hugomg Dec 12 '11 at 13:00
    
I have to disagree that it is a lot of work for little benefit. I believe it is a modest amount of work for a modest to substantial benefit. We already have ux behaviors written in plain jQuery, and have found ourselves duplicating a lot of script. We could just refactor to move common scripts into functions, but the extra step of making them unobtrusive means that developers do not have to write code to invoke the functions & initialize the behaviors. However you are right, the refactoring has no added benefit to users. –  danludwig Dec 12 '11 at 13:11
show 1 more comment

3 Answers 3

up vote 4 down vote accepted

It's a common pattern, "unobtrusive javascript" is a widespread name for it, and it's generally considered superior the alternatives (putting JavaScript calls directly into links and event handlers).

The only disadvantage that I can think of is that it makes the behaviour harder to discover. When looking at the HTML, you have no idea what the dynamic behaviour is or even where it's defined. This can be mitigated by conventions or IDE support.

share|improve this answer
    
+1 for the discoveribility trad-eoff, that hadn't occurred to me either. –  danludwig Dec 11 '11 at 19:33
    
That's why we put everything in 1 file. !@#$ IDEs. One big giant megadocument and ctrl-f FTW! –  Erik Reppen Oct 17 '13 at 5:50
add comment

There are two major disadvantages.

   1.  The first one was already mentioned by Michael Borgwardt: the fact that it's hard to discover what makes a page element acting as it does. For example:

<div id="TopActions">
    <a id="ToggleTopPanel" onclick="javascript:ToggleTopPanel();">Expand</a>
</div>

is straightforward: when reading this code, I an absolutely sure:

  • That when I click on "Expand" link, it will do something which is specified in ToggleTopPanel() method written somewhere. If I want to know more, I have just to search for the method.
  • That the page will not work with JavaScript disabled.

If, on the other hand, I read:

<div id="TopActions">
    <a id="ToggleTopPanel" href="?topPanel=expanded">Show</a>
</div>

I have no idea what will happen if JavaScript is enabled (and even if the behavior is different from the non-JavaScript version). Moreover, there is nothing I can do to find it with no effort. If there are thousands of lines of code, where to search? It could be:

$('#ToggleTopPanel').click(function() {
    // The magic happens here.
});

or maybe:

$('#TopActions a').click(UI.Top.Activated($(this)));

or something totally different. Either I have a browser with a profiler and I know how to use it, or, well...

   2.   The second reason is that unobtrusive JavaScript is not the easiest way to do the work. If it is obviously a choice for large-size web applications, it is an overkill for a small personal website visited by one person per week (excluding the person who created it).

  • If the deal is to make something small, and to make it fast and inexpensive, don't bother with unobtrusive JavaScript.

  • If the the deal is to add some annoying visual effects like those snowflakes flying all over the page or the bees hunting the cursor or the advertisement jumping in front of the page the user was about to read, don't bother with unobtrusive JavaScript.

share|improve this answer
    
+1 good point about the scale of the application, I should have mentioned that. It would definitely be pointless to use an approach like this on a 1 page (or very small) site. –  danludwig Dec 12 '11 at 13:14
    
I disagree with point 2. I've always found unobtrusive easier to work with, maintain, modify. Even in 1-3 throwaway contest apps for interactive agencies. With unobtrusive even in a smaller app I can typically very quickly get an overview of what's being applied where across the entire app. With inline, I just have a bunch of functions to look at. Dom methods and/or jq spells things out succinctly and I can modify in one place and get results everywhere. I don't even see how it's more effort. Classes are usually shorter than functions and often share dual use with style decs. –  Erik Reppen Oct 17 '13 at 5:59
add comment

This is called injecting functionality into an application. It's a "common" pattern.

I personally use a similar pattern

["feature1", "feature2", ...].forEach(function(feature) {
  var elems = $("." + feature);
  // this document has an element that uses the feature
  if (elems.length) {
    loadFeatureByAjax(document, feature);
  }
});

Then each feature knows how to inject itself into the selector

var Feature = function (selector) {
    $(selector).find('.featureName').datepicker();
}

Note that we use classes rather then data- attributes because attribute CSS selectors are slow as hell and should be avoided.

The only other objection is that your particular implementation feels verbose, but might just be your coding style.

share|improve this answer
    
+1 for the attribute selector performance, that hadn't occurred to me, thanks. –  danludwig Dec 11 '11 at 19:31
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.