How to make your generated widget’s DOM IDs reflect their AMD module

In the new AMD world, it’s suggested that we omit the specification of a “declaredClass” in our custom widget’s declare() call, like so:

define(["dijit/_WidgetBase"], function(_WidgetBase) {
    return declare([_WidgetBase], { 

    })
});

However, in this case, _WidgetBase doesn’t have a specified value for declaredClass, and uses the declaredClass from an appropriate parent class to automatically generate a DOM ID.

I’ve worked around this so far by using a pattern like this:

define(["module", "dijit/_WidgetBase"], function(module, _WidgetBase) {
    return declare(module.id, [_WidgetBase], { 

    })
});

Hopefully we’ll see some fixes from Dojo here to make this easier in future.

Destroy all widgets/dijits in a DOM node

Following up on Tom’s post from 2011, and taking into account the comments posted, here is the latest “known good” technique.

Often we need to empty a DOM node of all widgets. Here’s the magic incantation.

require(["dijit/registry", "dojo/dom-construct", 
        "dojo/_base/array"], 
        function(registry, domConstruct, array) {

    // Your DOM node reference goes here
    var node = null; 

    // Destroy the widgets, including their
    // children and DOM fragments
    array.forEach(registry.findWidgets(node), 
        "item.destroyRecursive()");

    // OPTIONAL: Explicitly empty the node.
    // This will take care of DOM nodes that 
    // weren't managed by widgets
    domConstruct.empty(node);

});

dojox/mobile :: Programmatic View transitions

When programmatically initiating View transitions, we have two choices. Given the following markup, we can initiate a transition between view1 and view2 in two ways.

<div data-dojo-type="dojox/mobile/View" id="view1" selected="true">
   stuff
</div>
<div data-dojo-type="dojox/mobile/View" id="view2">
    more stuff
</div>

Option 1: View.performTransition()

dijit.registry.byId("view1").performTransition("view2", 1, "slide");

See the dojox/mobile/View API for full details.

Option 2: new TransitionEvent().dispatch()

require(["dojox/mobile/TransitionEvent"], function(TransitionEvent) {
    var view1 = dijit.registry.byId("view1");
    new TransitionEvent(view1.domNode, {
        moveTo: "view2",
        transition: "slide",
        transitionDir: 1
    }).dispatch();
});

See the dojox/mobile/TransitionEvent API for basic details.
It is possible to write a basic wrapper around this function to simplify your code.

Which to use

Option 1 (View.performTransition) looks simpler, but it does not handle transitioning to nested views correctly in some cases, leaving ancestor views invisible.

Option 2 (new TransitionEvent) is recommended. It handles these edge cases correctly, establishing the correct “from” and “to” views, and ensuring ancestor views are visible.

Dojo widget property setters and attributeMap’s replacement

As we create widgets to accomplish a task, we often need to contain other widgets. Creating a simple way to configure contained widgets via the containing widget’s API is often accomplished using custom _setXXXAttr functions.

However, Dojo provides alternative methods to achieve this. It provides the attributeMap feature, though this is deprecated and shall be removed in version 2.0. Since version 1.7, Dojo has provided a new syntax for _setXXXAttr that allows usage of attributeMap-style configurations.
Continue reading

Using dojox “hold” gestures inside Scrollable areas

I have recently needed to embed widgets that react to “hold” gestures in ScrollablePanes.

Particularly when the widgets fill the ScrollablePane, this can create some problems where a user drags the ScrollablePane to scroll.  Often, a “hold” event is generated for a contained widget during the scrolling action, which may be undesired.

The following code uses dojo/aspect to monitor the scrolling state of all ScrollablePanes on the page.

require(["dojo/aspect", "dojox/mobile/ScrollablePane"], function(aspect, ScrollablePane) {
    // For demonstration purposes, we use a global variable here to hold the scrolling state for all ScrollablePanes
    // You may wish to track by ScrollablePane instance instead
    mypackage.myapp.isScrolling = false;
    aspect.before(ScrollablePane.prototype, "addCover", function() {
        // "this" is the ScrollablePane instance
        mypackage.myapp.isScrolling = true;
    });
    aspect.after(ScrollablePane.prototype, "removeCover", function() {
        // "this" is the ScrollablePane instance
        mypackage.myapp.isScrolling = false;
    });
});

Once this monitoring has been added, it is now simple to guard the contained widgets’ “hold” event handlers by inspecting mypackage.myapp.isScrolling.

Bootstrapping Dojo for debug, and CSS3 PIE

Dojo debug bootstrap

I often find that I need to get really basic console access to a Dojo bootstrap page, to test out Dojo’s core functions, etc. Finding a page where I can do this quickly can be a pain.

With this in mind, I’ve put together a barebones page that will load a requested version of Dojo core into memory. It supports all the versions of Dojo hosted by the Google Libraries API.

You can access this page here:

http://dojobootstrap.tk

To load a specific version of Dojo, try appending the version to the path like so:

http://dojobootstrap.tk/1.5

CSS3 PIE

The eagle-eyed among you will notice that in Internet Explorer < 9, elements in the bootstrap page still have rounded corners. This is down to use of CSS3 PIE, a great project that aims to retrofit the more useful (read: requested by clients) CSS3 decorations to IE 6-9; border-radius, box-shadow and linear-gradient backgrounds.

The project just works and the documentation is great. This finally puts to bed the spectre of ugly background-image hacks in IE. Give it a try.