Login Register

Direct Extension

Every widget class is a Dojo class. So you should be able to extend a widget class just like you would any other Dojo class, right? Like with dojo.declare? Absolutely!

What do you gain by using dojo.declare instead of dijit.Declaration? Mostly you gain flexibility. For example, say you wanted to declare a widget class with the same functionality, but two completely different versions of a template based on a user preferences. No problem. You construct the template itself with JavaScript code, then pass it to dojo.declare in the template property.

But let's get back to ImageAccordion. Following the examples in Modules, we'll place this class dojoc.layout.ImageAccordion in a file named dojoc/layout/ImageAccordion.js under the Dojo root. Here's how to write it in code:

// all packages need to dojo.provide() _something_, and only one thing
dojo.provide("dojoc.widget.ImageAccordion");
// AccordionContainer is the module with dijit.layout.AccordionPane
dojo.require("dijit.layout.AccordionContainer");
// our declared class
dojo.declare("dojoc.widget.ImageAccordion",
        // we inherit from this class, which in turn mixes
        // in _Templated and _Layout
        [ dijit.layout.AccordionPane ],
        // class properties:
        {
        templatePath: dojo.moduleUrl("dojoc","layout/templates/ImageAccordion.html"),
        // Necessary to keep Dijit from using templateString in AccordionPane
        templateString: "",
        // src: String
        //      src url for AccordionPaneExtension header
        src: ""
});

The src string does pretty much what we think - unlike with dijit.Declaration, we must declare the new attributes explicitly. The templatePath requires some explanation.

Attaching the Template to a Direct Extension

With dijit.Declaration, the template is just the body of the tag. In dojo.declare land, there are three ways to specify a template:

  • Use the templatePath attribute to point to a URL with a template in it.
  • -OR- Specify the template directly in the templateString attribute
  • -OR- Pass a DOM node with a parsed representation of the template

The first option is preferred because it separates the JavaScript and HTML code cleanly. With templateString, you must remember to escape all the quote marks, required in a JavaScript string. The Custom build system will convert the template in templateUrl to an inline templateString to help performance, so no need to worry there. Note: as in our above example, if you are overriding a widget with a templateString, and you want to use a templateUrl in your subclass, be sure to set templateString to "".

The templates are stored in the module along with all the JavaScript code. We place this template file into dojoc/widgets/template/ImageAccordion.html:

<div class='dojocImageAccordion'
        >
<div dojoAttachPoint='titleNode,focusNode'
dojoAttachEvent='ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus'
                  class='dojocImageAccordionTitle' wairole="tab"
                >
<img alt="${title}" src="${src}"
        >
</div
        >
<div><div dojoAttachPoint='containerNode'
                style='overflow: hidden; height: 1px; display: none'
                class='dojocImageAccordionBody' waiRole="tabpanel"
        >
</div></div>
</div>

Option 3

I don't see any details here on how to achieve Option 3 ('Pass a DOM node with a parsed representation of the template"). Is this related to the src="" attribute?

thx.

Errors in JS and the template

Few problems:

1) In the JavaScript
dojoc.widget.ImageAccordion should be dojoc.layout.ImageAccordion

2) I only see ${title} for dojoc/widgets/template/ImageAccordion.html (using FireFox 2.0.0.13). I had to view the source to determine what the template should be.

3) The template doesn't look right. It uses custom CSS classes.

Here are the artifacts of the example:

1) HTML file - You may need to fix the relative paths. It references an image file that needs to change. My project structure was:

Project Name
 |_examples
 |   |_ misc
 |       |_ ProgrammaticWidgetExtension.html
 |_dojoc
 |   |_ layout
 |        |_ templates
 |        |      |_ ImageAccordion.html
 |        |_ ImageAccordion.js
 |_other dojo directories (i.e. dojo/dijit/dojox)

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Programmatic Widget Extension</title>
 
    <script type="text/javascript" src="../../dojo/dojo.js"
                djConfig="parseOnLoad: true">
</script>
    <script type="text/javascript">
        dojo.require("dojo.parser");
        dojo.require("dijit.Declaration");       

                dojo.require("dijit.layout.LayoutContainer");      
                dojo.require("dijit.layout.AccordionContainer");
               
                dojo.registerModulePath("dojoc","../dojoc");
                dojo.require("dojoc.layout.ImageAccordion");
               
    </script>

        <style type="text/css">
                @import "../../dojo/resources/dojo.css";
                @import "../../dijit/themes/tundra/tundra.css";
                @import "../../dijit/demos/mail/mail.css";
                @import "custommail.css";
        </style>

</head>
<body class="tundra">   
        <div dojoType="dijit.layout.LayoutContainer" id="main">
                <div dojoType="dijit.layout.AccordionContainer" sizeMin="20" sizeShare="20" layoutAlign="client">
                        <div dojoType="dojoc.layout.ImageAccordion" title="Folders" src="../postman/folder.gif">
                            Folders will go here
                        </div>
                       
                    <div dojoType="dijit.layout.AccordionPane" title="Address Book">
                          Addresses go here
                        </div>     
                </div>              
        </div>
</body>

2) Java script file

// all packages need to dojo.provide() _something_, and only one thing
dojo.provide("dojoc.layout.ImageAccordion");
// AccordionContainer is the module with dijit.layout.AccordionPane
dojo.require("dijit.layout.AccordionContainer");
// our declared class
dojo.declare("dojoc.layout.ImageAccordion",
        // we inherit from this class, which in turn mixes
        // in _Templated and _Layout
        [ dijit.layout.AccordionPane ],
        // class properties:
        {
        templatePath: dojo.moduleUrl("dojoc","layout/templates/ImageAccordion.html"),
        // Necessary to keep Dijit from using templateString in AccordionPane
        templateString: "",
        // src: String
        //      src url for AccordionPaneExtension header
        src: ""
});

3) ImageAccordion.html:

<div class='dijitAccordionPane'
        >
<div dojoAttachPoint='titleNode,focusNode'
                        dojoAttachEvent = 'ondijitclick:_onTitleClick,onkeypress:_onTitleKeyPress,onfocus:_handleFocus,onblur:_handleFocus'
                        class='dijitAccordionTitle' wairole="tab"
                >
<div class='dijitAccordionArrow'></div
                >
<img alt="${title}" src="${src}"/> ${title}</div
        >
<div><div dojoAttachPoint='containerNode'
                                style='overflow: hidden; height: 1px; display: none'
                class='dijitAccordionBody' waiRole="tabpanel"
        >
</div></div>
</div>

Hope this will help someone

When extenting another

When extenting another Widget, does one have to be careful of overriding its parents methods i.e. the 'startup' method perhaps or does dojo.declare take care of this?

yes and no

sometimes you _want_ to override a method, so dojo.declare does that. sometimes you want to call your own code of the method before or after, and this.inherited does that:

dojo.declare("my.Thinger",dijit.Dialog,{
   startup:function(){
        /* my code */
        this.inherited(arguments); // "arguments" is key
        /* and / or more code */
   }
});

So, one must explicitly

So, one must explicitly call
this.inherited(arguments);
in order to invoke the parent function o the same name. Is this then considered good practice if one doesn't fully understabd the functionality of the parent?

shouldn't the empty templateString

be above the templatePath?