HTML Widget Prototyping with the Dojo Toolkit

By on November 2, 2007 10:58 am

The first Dojo Toolkit 1.0 Release Candidate is complete. To celebrate, let’s take a look at one of the new features in Dijit’s dijit.Declaration.

We are already familiar with Dijit’s capabilities to render widgets in markup. This is a powerful way of providing widgets in your page with about the same effort as styling with CSS. Recently, Alex Russell blogged about new Dojo alternate script types as a way of attaching code via markup through a creative use of the script tag’s type attribute. One of the newest features in the Dojo Toolkit, dijit.Declaration, extends that approach by giving us a way to define widgets in markup.

Let’s start with a bare-bones HTML document that includes the Dojo Core, dojo.parser, and Dijit. The new parameter “parseOnLoad=true”, included as part of the djConfig attribute in our initial script tag, tells the dojo.parser to go to work. It’s the standard mechanism used when defining a user interface using the markup versions of Dijit constructors. We then include our resources: dijit.Declaration and the dojo.parser.










Now, within the body tag, we will create a placeholder for the widgets that we will be defining. This will be the definition of our widget.

We have created our root element, and gave it a dojoType of dijit.Declaration. This tells the dojo.parser that we intend for this to be the declaration of a widget, including the widget’s template. The widgetClass is the name of our widget, and we have set a property default of defaultText to an empty string. Note the defaults object is in quotes.

If we tried to display the page now, it will be blank. That’s because this is a declaration and the parser consumed it, converted into a constructor object, and is now waiting to be instantiated. In other words, we have to create the actual widget based on our template, emulating the new constructor:

Note that we called our widgetClass, and set the property. Now when we refresh the page, our widget is created:

Example of a widget created with dijit.Declaration

Our widget is displayed, and as you can see, the parser read in the template and found our placeholder for the defaultText property, and replaced it with the value.

Now that we have our markup widget, let’s give it some methods. Let us say if the user leaves a blank field, we want to insert the default text. We will use the alternate script types that Alex showed us:

Using a script-type of dojo/method, the browser skips the script. The dojo.parser then picks it up and converts it to code and inserts it into our widget. Since this is a method type, we’re creating a function, which fires on the onchange event we attached to the input node.

Let’s finish it up. On creation, we will lighten the font color, and when a user clicks on the field, the default text is removed:

Note that to tie into the creation of the widget, we used dojo/connect and, using the Dojo event method “dojo.connect” behind the scenes, connected to the native postCreate method of the widget. Then we created another method, and wired that up to the additional event we attached: onfocus.

Additionally, you could create a base form widget, and extend that with various input and buttons widgets. To extend another markup widget, you would use the mixins method, which might look something like this:



Validation and user feedback can be written, coded, and styled all on the same page. You can see the possibilities of this technique, not only with form fields but with page layouts and more, all quickly prototyped without the need for an extensive supporting infrastructure.

Comments

  • Congrats on the 1.0 release. dijit.Declaration definitely looks useful. I’ll have to explore it this weekend.

  • From a technical standpoint, this looks very cool. However, what I’m not clear on is ‘why’ one would want to do this. Is it not just one more abstraction away from JavaScript? Since this code would have to be placed on every page that it is used, the user will have to download the code again and again, with no caching. For a very small widget this may not be an issue, but for a widget with multiple complex methods, this could become a serious performance problem.

    I guess I just don’t see the advantage of this approach, over the standard pattern of declaring a JavaScript widget, having it compressed and gzipped, then cached client side. Once anything complex has to be done, you still have to write quite a lot of JavaScript, only you declare the functions with a tag instead of in JavaScript.

    I’m sure I’m missing the point somehow, but if I am, then so are others….

    Oh, and congrats to all the Dojo team (and me! :-) ) on the 1.0 release.

  • @Shane: You’re observation is definitely reasonable. I’m more of a “reporter” of this technique, so this is strictly my opinion:

    It’s obviously not good for large apps for precisely the reasons you state. As I prepared for this blog I considered what they best uses may be. Naturally I blogged on what I thought best – maybe page layouts and other things that need to be tended to once or twice on a page.

    I think this is a new idea, and it’s a great thing to throw out there and see what users do with it and perhaps it will lead to something we haven’t thought of.

    However, I think the real story is in Alex’s alternate script types. When I first heard about that a while back, I got quite excited, as I think that has a lot of potential. Dijit.Declaration would be just one example.

  • ttrenka

    Hi Shane,

    The basic idea behind it is less production deployment and more *very* rapid prototyping; instead of having to set up the infrastructure for a custom widget, you can do it all inline in a single page and work it up from there. Once you’re satisfied with the basics of the widget, you can then turn around and do your normal custom widget split up (with your JS, HTML and CSS stuff) based on it.

  • Hi Tom,

    Thanks for the clarification.I can see how this would be a very quick way to prototype something. However, it would be nice if the developer was able to reuse this code once, the prototype phase is completed.

    A couple of ideas:

    1. Make it possible to extract the dijit.Declaration code out into a file, which can then be pulled in via dojo.require, and instantiated. This would be relatively simple to do – just fetch the text, append it to the tag, and instantiate it as usual.

    Much more interesting in my mind is:
    2. Add an XSLT transform to the Dojo build system so that widgets/dijits declared in this manner, in their own file with some custom extension (.dijit, whatever) and written out as a .js file, all nicely transformed into a JavaScript object. This would allow developers to decide what paradigm they’d like to write in – pure JS, or an XML based syntax – and stick to that.

    Another advantage of the second approach is that users are insulated from changes to the Dijit infrastructure in future releases. If their custom code is encapsulated in tags, with templates and attachPoints defining their HTML layout, then the rest of the code can be defined by the XSLT transform, and the generated code will always conform to the latest API.

    Of course, these options are in no way mutually exclusive.

    This may seem like a “I hate JavaScript and would like someone else to write it for me” comment, but it’s not. I doubt I would personally use this, but I figure that if you’re going to go this far, and introduce an abstraction, why not go the extra 10% and get all these extra benefits?

  • The other thing about the Declaration widget is that its great for developing widgets with complex templates, and especially where you need some paramaterization of the template on the server-side. As the element /is/ the template for a Declaration, that template can be generated the same way as you generate the rest of the page, without having to deal with escaping and concatenating html in strings.

    I’ve found it most useful for the “last mile” in a widget inheritance chain, where you inherit from something that does pretty much everything you need, and just supply a specialized template and perhaps some constructor code or an onClick method or something – and keep it right inline with the rest of the page/html it belongs with.

  • Pingback: SitePen Blog » Blog Archive » Dissecting Dijit()

  • rb

    This code does not appear to work for dojo 1.0.2. Can anyone shed any light on this?

    Code as I understand it:

    
    
        InlineEdit Demo
        
            @import "dojo/dijit/themes/tundra/tundra.css";
            @import "dojo/dojo/resources/dojo.css";
        
        
        
            dojo.require("dijit.Declaration");
            dojo.require("dojo.parser");
        
    
    
    
    begin.
    
    
    
        
        
            this.tNode.style.color = "#CCCCCC";
        
        
            var txt = dojo.trim(this.tNode.value);
            console.log("CNG")
            if (txt.length == 0) {
                this.tNode.value = this.defaultText;
                this.tNode.style.color = "#CCCCCC";
            }
        
        
            alert("focus!");
            if (this.tNode.value == this.defaultText) {
                this.tNode.value = "";
                this.tNode.style.color = "#000000";
            }
    

    End.

  • rb

    I think it would be helpful to have final sample code, not just fragments. This works for a local copy of 1.0.2:

    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
    <html>
    <head>
        <title>InlineEdit Demo</title>
        <style type="text/css">
            @import "dojo/dijit/themes/tundra/tundra.css";
            @import "dojo/dojo/resources/dojo.css";
        </style>
        <script type="text/javascript">
            djConfig = {
                isDebug: true,
                parseOnLoad: true,
                baseUrl : 'dojo/dojo/'
            };
        </script>
        <script
                type="text/javascript" src="dojo/dojo/dojo.js">
        </script>
        <script type="text/javascript">
            dojo.require("dijit.Declaration");
            dojo.require("dojo.parser");
        </script>
    </head>
    <body class="tundra">
    
    <div dojoType="dijit.Declaration"
         widgetClass="TextField" defaults="{defaultText:''}">
        <input type="text" dojoAttachEvent="onchange, onfocus, onblur"
               dojoAttachPoint="tNode" value="${defaultText}"/>
        <script type="dojo/connect" event="postCreate">
            this.tNode.style.backgroundColor = "#FF99CC";
        </script>
        <script type="dojo/method" event="onchange">
            var txt = dojo.trim(this.tNode.value);
            console.log("CNG")
            if (txt.length == 0) {
                this.tNode.value = this.defaultText;
                this.tNode.style.backgroundColor = "#c0c0c0";
            }
        </script>
        <script type="dojo/method" event="onfocus">
            if (this.tNode.value == this.defaultText) {
                this.tNode.value = "";
                this.tNode.style.backgroundColor = "#ffcc00";
            }
        </script>
        <script type="dojo/method" event="onblur">
            this.tNode.style.backgroundColor = "#ff9900";
        </script>
    </div>
    
    
    <div dojoType="TextField" defaultText="Type Here"></div>
    
    
    </body>
    </html>
    
  • Hello, i am having problems creatign object from declared classes.
    i use the same declaration as above.
    but, would lice to create a widget programmaticaly.

    var f1=new dijit.form.Button({ “class”: “large”, style: “color: red” },
    dojo.byId(“test”));
    var t1=new TextField({defaultText:”hallo”, var1:11}, dojo.byId(“test2”));

    the first creation works well (dijit.formButton)
    the second does not.
    i get following error:
    TextField is not defined

    has some one an idea how to solve this?

    thanks a lot!

  • I am facing the same issue as that of mojo.

    var t1=new TextField({defaultText:”hallo”, var1:11}, dojo.byId(”test2″));

    How to create of object of this declaration class.

    I need to update/refresh data of my widget so what I am looking for is to destroy the existing object and new object.

    Any idea how that can be achieved ?

  • mojo:
    I’m guessing you didn’t put the “new TextField” code in a dojo.addOnLoad() – because this worked for me. “test2” is an entirely different dom node, correct?

    vijay:
    Firstly, make sure you are destroying the actual widget, and not the node that was used for the declaration (which will go away, leaving just code).
    Secondly, the problem doesn’t seem to so much be in dijit.Declaration, as much as finding the node. When you create and then destroy a widget, that node is gone. “test2” becomes the domNode of the widget, and then when you destroy it, it destroys “test2” completely. To do what you are attempting, you’ll need to recreate the node.

  • vijay

    Thanks mwilcox for your reply,
    I worked out on creating new widget instance.

    Now I am not understanding one thing,
    How can I add node to a tree, dynamically.
    I tried this tutorial

    http://willcode4beer.com/ware.jsp?set=dojoRpcTree

    and in short it ask to do something like this

    var store = new dojo.data.ItemFileWriteStore({url:”some_url”});
    var tree = new dijit.Tree({store:store,query:{type:’folder’} ,childrenAttr:”folders” });
    var newTree = new dijit.Tree({store:store, query:{type:’folder’} ,childrenAttr:”folders” });

    tree.addChild(newTree,0); //here I am getting error

    working demo can be like this
    http://willcode4beer.com/pages/ware/dojo/rpcTree2.html

    Any idea how to add a node dynamically to a tree ?

  • Vaibhav

    Hi mike,
    This is a great feature i came up with. One thing i want to ask. I love to make dojo type widgets in the js file itself using dojo.declare and extending the dojo.widget and template.

    If i dont want to use the html or jsp file at all except for forwarding can we declare the our own dojo widgets in js too

    cheers,
    Vaibhav

  • Hi!
    Actually i have one image in our application and our application is serving that image.but the problem is we have different Sizes of images.Currently we are using the .With it is not possible to resize it as per the image because sometime we are serving the big image and sometime we are serving the small image. is it possible to solve this issue ?, So that i will serve my image dynamically with dojo. so that it takes the window size as per the image size.
    Thanks in Advance!

  • moicap

    Hi!
    I think its refreshing to read about efforts to implement stuff through dojo. Though hence writing it in markup, then having a parser evaluate to javascript, and then evaluate the script methods themselves in the browser.. That will never be able to compete with tailored use of the API instead.
    Anyways, the thing is! Ive been looking for customizable form fields, and the pr. pageload declaration of widgets inline, really – i mean really increase custumization.

    Allthough i would still suggest writing an ui-script, with use of the API instead of using parser.js – any thoughts on efficiency here? I’d have to agree with Vaibhav (16th), thats the way to do it, objectoriented javascript 8)

    cheers

  • Hi, I love so much dojo since I went to sun tech days in Mexico city but something that I don’t like so much is the “dojoType” attribute that must be added to every widget I wanto to create, this because I have to break the standards. I have been using jquery and the plugins of it and I like so much the “selectors” they use, maybe if dojo can implement something like this and transform a simple textbox or div element into a widget it would be a better javascript framework, even to make the plugins or addons in dojo is more difficult than in jquery, this is a suggestion, hope dojo developers can make it real.

  • Hi Omar.
    Glad you like dojo. dojoType is very popular with people who are not compfortable with the JavaScript skills, and server side coders who can insert widgets via markup.

    But dojoType is optional. I prefer all of my code to be outside of markup myself. And if it is, it validates does it not?

    I whipped up a plugin for you that would be standards compliant:

    var plugin = dojo.declare(“MyInput”, null, {

    defaultText:””,
    constructor: function(props, node){
    this.defaultText = props.defaultText;
    this.domNode = dojo.byId(node);
    dojo.connect(this.domNode, “blur”, this, “onBlur”);
    dojo.connect(this.domNode, “focus”, this, “onFocus”);
    this.domNode.value = this.defaultText;
    },
    onBlur: function(){
    this.domNode.value = “”;
    },
    onFocus: function(){
    if(!this.domNode.value){
    this.domNode.value = this.defaultText;
    }
    }
    });

    dojo.addOnload({
    var mywidget = new MyInput({defaultText:”Put text here”}, “mytext”);
    });