Mucking Dijit
by Peter Higgins

Ever so often I want Dijit to behave just slightly different than the defaults, or need
to shim some added checks or setup to existing methods in the dijit. There are three really rapid ways to easily customize the Dijit code, each with different results and different use cases. Enter dojo.extend, dojo.mixin, and dojo.declare.


Expanding on a simple setTitle dijit.Dialog extension on the Dojo Forums. The example uses dojo.extend to directly modify the Dialog’s prototype, giving the setTitle method to any and all Dialogs created in the page:

dojo.require("dijit.Dialog");
dojo.extend(dijit.Dialog,{
     setTitle: function(/*string*/title){
         this.titleNode.innerHTML = title || "";
     }
});

The second method would give a setTitle method to a particular instance of a Dialog, using dojo.mixin to “mix” the method into the object, or in this case instance:

dojo.require("dijit.Dialog");
dojo.addOnLoad(function(){
     var dialog = new dijit.Dialog({ title:"test" });
     dialog.startup();
     dojo.mixin(dialog,{
          setTitle:function(title){
               this.titleNode.innerHTML = title || "";
          }
     });
});

the third and most configurable way: “subclassing” (or more literally, inherting) via dojo.declare.

dojo.provide("my.Dialog");
dojo.require("dijit.Dialog");
dojo.declare("my.Dialog",dijit.Dialog,{
     setTitle:function(title){
          this.titleNode.innerHTML = title || "";
     }
});

This creates a new widget named my.Dialog leaving the actual dijit.Dialog unmodified, and without having to know which instance you want to have a setTitle method.
You can also use this technique to override default dijit behavior by mixing/extending a method with an existing name.

Finally, if you want to simply “add code” to an existing method, you simply call the inherited() method:

dojo.require("dijit.Dialog");
dojo.declare("my.Dialog",dijit.Dialog,{
     canBeShown: true,
     // extend the default show() method
     show:function(){
            if(this.canBeShown){
                    this.inherited(arguments);
            }
     }
});

now you can set .canBeShown = false on any my.Dialog instance, and the three new lines will prevent the “original” show() method from executing. You must pass the arg: “arguments” to inherited() so the superclass has a way of knowing the name of the function which called it (arguments.callee)

Tags: , ,

This entry was posted on Monday, February 25th, 2008 at 3:19 pm and is filed under Dojo Cookies. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

4 Responses to “Mucking Dijit”

  1. dsnopek Says:

    Great article! This sort of extension should be a part of any JavaScript developers personal tool set.

    However, doing this sort of extension on someone else’s library (ie. dijit), worries me when it deals with internal implementation details. After all, “titleNode” used in your examples (as far as I know) is not a documented part of dijit.Dialog. You can only know about this by reading the code. When a new version of dijit comes out, it is not guaranteed to be there.

    I recently wrote about this topic in my blog (coincidentally also concerning dijit.Dialog):

    http://www.hackyourlife.org/?p=28

    (FYI: I did end up abandoning my “forked” version of dijit.Dialog and ended up using dojo.extend() and other mucking about with internals).

    The particular issue with dijit.Dialog isn’t the point. Its that I seem to end up extending all dijit’s I use in little ways and its starting to worry me the amount of things that will likely break when updating to newer versions.

    If this is going to be the “officially sanctioned” method of customizing dijit’s, then users really need to have their internals officially documented and some kind of promise with regard to when and how these APIs can be broken.

    Cheers!
    David Snopek.

    http://www.hackyourlife.org/

  2. Hack Your Life » Blog Archive » Memorati revamp live! (and dijit.Dialog update) Says:

    [...] follow-up on my dijit.Dialog comments (and here!), I ended-up abandoning my fork. I decided that the original positioning algorithm was acceptable, [...]

  3. pegli Says:

    Great article! This was just what I needed to solve my problem, which I’ll describe here in case anyone else runs into the same issue. I am working on an app that pulls JSON data from a server and puts it into a form for editing. The dijit.form.Form class has a handy method that does exactly this called setValues(obj) which iterates over the properties of obj and calls setValue on the form widget whose name matches the name of the object property. This worked great for string and numeric properties of my object, but some of the fields in the object to be edited are dates. JSON doesn’t specify a notation for date objects — all dates are encoded as strings in some (hopefully) parsable format. I wanted to put the dates into dijit.form.DateTextBox form widgets, naturally, but when Form.setValues(obj) called DateTextBox.setValue() with a string, I got an error.

    The solution was to subclass DateTextBox as follows:

    dojo.require(”dijit.form.DateTextBox”);
    dojo.declare(”my.dijit.form.DateTextBox”, dijit.form.DateTextBox, {
    setValue: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue) {
    value = new Date(value);
    this.inherited(arguments);
    }
    });

    What isn’t mentioned in your article is that it is possible to change argument values before calling this.inherited(arguments). I can’t say that I looked into this in detail, but resetting “value” to a Date object worked fine and the proper date was displayed in the form.

    Thanks again!

    p.

  4. Sanmao的幸福(?)生活 » Blog Archive » 扩展标准的 Dijit 控件 Says:

    [...] 参考资料:Mucking Dijit [...]

Leave a Reply

You must be logged in to post a comment.