Boilerplate reduction

22 May

I find myself rewriting some common boilerplate in my code, and have recently started using Dojo’s partial() and getObject() functions instead:

Extract deep properties from an array of objects
Boilerplate

dojo.map(array, function(i) { return i && i.foo && i.foo.bar && i.foo.bar.baz; ));

Trick
dojo.map(array, dojo.partial(dojo.getObject, "foo.bar.baz", false));

Additionally, I stumbled across this little nugget:

Filter out “empty” elements from an array
Boilerplate

dojo.filter(array, function(i) { return !!i; ));

Trick
dojo.filter(array, Boolean);

Tags:

Staying in the errback chain when chaining Deferreds using then()

19 Apr

I’m gearing up for an article explaining how Deferred chains move between errback and callback chains, and how to deal with some of the more esoteric issues we all come up with.

For now, an interesting snippet:

// Create a dummy deferred in the error state
var d = new dojo.Deferred();
d.errback(new Error("FAIL"));
// And start chaining
d = d.then( function(response) { 
  console.log("success1 :: " + response); 
}, function(error) { 
  console.log("error1 :: " + error); 
});
d = d.then( function(response) { 
  console.log("success2 :: " + response); 
}, function(error) { 
  console.log("error2 :: " + error); 
});

Through reading various articles online, I expected that flow would stay in the errback chain, and error2 would fire with the original error as an argument. However, in all versions of Dojo, the above code will result in:

error1 :: Error: FAIL
success2 :: undefined

Unexpected. If we explicitly return the Error that was originally provided to the first errback function, like so:

// Create a dummy deferred in the error state
var d = new dojo.Deferred();
d.errback(new Error("FAIL"));
// And start chaining
d = d.then( function(response) { 
  console.log("success1 :: " + response); 
}, function(error) { 
  console.log("error1 :: " + error); 
  return error;
});
d = d.then( function(response) { 
  console.log("success2 :: " + response); 
}, function(error) { 
  console.log("error2 :: " + error); 
});

We get:

error1 :: Error: FAIL
success2 :: Error: FAIL

Some online articles state that returning an Error from a callback or errback function will cause the flow to move into the errback chain. This is actually true only when using traditional addCallback() and addErrback() functions.

So, when using then(), we need to do the following:

// Create a dummy deferred in the error state
var d = new dojo.Deferred();
d.errback(new Error("FAIL"));
// And start chaining
d = d.then( function(response) { 
  console.log("success1 :: " + response); 
}, function(error) { 
  console.log("error1 :: " + error); 
  throw error;
});
d = d.then( function(response) { 
  console.log("success2 :: " + response); 
}, function(error) { 
  console.log("error2 :: " + error); 
});


error1 :: Error: FAIL
error2 :: Error: FAIL

This will result in some extra errors in your console log. But it may make things work as you expect.

For more information, and some quite detailed test cases, take a look at the dojo.Deferred tests.

Tags: , , , , , , ,

JSON Schema

8 Apr

I’ve just published an article over at IBM’s developerWorks outlining how using JSON Schema can help you increase the robustness of your browser-server communications.  I used this technique on a large client engagement recently to great effect.

You may also find the JSON Schema Lint tool of use for developing your own schema.

Replacing models at runtime with dojox.mvc

7 Mar

When using dojox.mvc, I’ve frequently needed to replace my model at runtime. Here’s a quick snippet on how to do this.

Continue reading 

Tags: , , ,

Making nested dojox.mvc.Repeat tags work in Dojo 1.7

7 Mar

If you’ve done anything complex with dojox.mvc in 1.7, you’ll find a fairly intricate use case with nesting dojox.mvc.Repeats – without extra config, this will likely not work as you expect.

I recently solved this problem with assistance from Ed Chatelain (dojox.mvc author). Here is a working snippet.

Continue reading 

Tags: , , ,

More posts soon, I promise

17 Feb

Been away for a while traveling around the world, but now I’m back, and diving through all the changes and modifications that come with Dojo 1.7.

I hope to put some more posts up soon!

Tags: ,

Displaying and Styling a Read-only Dojo Tree Control

12 Sep

In this tutorial, we are going to be using the Dojo toolkit – a popular JavaScript tookit shipped with the IBM Feature Pack for Web 2.0 and Mobile. Specifically, we are going to be using the dijit.Tree class from the Dojo toolkit to display a simple Dojo read-only tree that can display information from a hierarchy of data. We’ll also style the tree, showing how to style different levels of the tree differently.

We’ll start out with a basic JavaScript object that contains some data we want to display. It’s hierarchical in nature – arrays inside arrays. In this example, we assume we are running an online retailer, and we want to display all the customers we have, and for each, all the orders they have made in the last month, then within those, each of the items in the order. Our object looks like this:

var customerOrderHistory = [
    {
        "name": "Fred Bloggs",
        "customerNum": 23,
        "orders": [
            {
                "orderNum": "0001",
                "items": [
                    {
                        "description": "Gone with the Wind (DVD)",
                        "itemNum": 56
                    },
                    {
                        "description": "Oxford English Dictionary",
                        "itemNum": 78
                    }
                ]
            },
            {
                "orderNum": "0002",
                "items": [
                    {
                        "description": "Whittaker's Alamanac",
                        "itemNum": 90
                    }
                ]
            }
        ]
    },
    {
        "name": "David Smith",
        "customerNum": 45,
        "orders": [
            {
                "orderNum": "0003",
                "items": [
                    {
                        "description": "King James Bible",
                        "itemNum": 112
                    }
                ]
            }
        ]
    }
];

Before we can create a Dojo Tree to display this data, we need to create a Tree Model. In our case, we’re going to use the dijit.Tree.ForestStoreModel to do this, as our tree has multiple roots (customers).

In turn, in order to create this tree model, we in turn need to get place our items into a Dojo data store (we’re going to use the dojo.data.ItemFileReadStore, as it’s well placed for handling in-memory data). To create this data store, we first need a data structure where each node and leaf in the tree has a consistent field name for its identifier (the internal representation of that node or leaf) – which must be unique across the entire tree – and a consistent field name for its label (what will be displayed on the screen for that node or leaf). Each node also needs to have a consistently named array that contains its child elements. Therefore, we need to write a data restructuring function. Our looks like this:

_restructureCustomerData = function(data) {
        var newData = dojo.map(data, dojo.hitch(this, function(customer) {
            var newCustomer = {};

            newCustomer.id = customer.customerNum;
            newCustomer.name = customer.name;

            newCustomer.children = dojo.map(customer.orders, dojo.hitch(this, function(idPrefix, order) {
		var newOrder = {};

		newOrder.id = idPrefix + "_" + order.orderNum;
		newOrder.name = order.orderNum;

		newOrder.children = dojo.map(order.items, dojo.hitch(this, function(idPrefix, item) {
		    var newItem = {};

		    newItem.id = idPrefix + "_" + item.itemNum;
		    newItem.name = item.description;

		    return newItem;
		    }, newOrder.id));

		return newOrder;
		}, newCustomer.id));

            return newCustomer;
        }));

        return newData;
    }

This will walk through the object tree of our initial data, and at each level will use the dojo.map function to create an entirely new resultant object tree, that consistently at each level uses the field names id (for the identifier) and name (for the label). Each non-leaf node also has a field called children that contains the child elements. For illustration, the resultant object looks like this:

[
    {
        "id": 23,
        "name": "Fred Bloggs",
        "children": [
            {
                "id": "23_0001",
                "name": "0001",
                "children": [
                    {
                        "id": "23_0001_56",
                        "name": "Gone with the Wind (DVD)"
                    },
                    {
                        "id": "23_0001_78",
                        "name": "Oxford English Dictionary"
                    }
                ]
            },
            {
                "id": "23_0002",
                "name": "0002",
                "children": [
                    {
                        "id": "23_0002_90",
                        "name": "Whittaker's Alamanac"
                    }
                ]
            }
        ]
    },
    {
        "id": 45,
        "name": "David Smith",
        "children": [
            {
                "id": "45_0003",
                "name": "0003",
                "children": [
                    {
                        "id": "45_0003_112",
                        "name": "King James Bible"
                    }
                ]
            }
        ]
    }
]

We can now use this object as the input to the creation of a data store:

var store = new dojo.data.ItemFileReadStore({
        data: {
            "identifier": "id",
            "label": "name",
            "items": restructuredData
        }
    });

And then in turn a store model:

var treeModel = new dijit.tree.ForestStoreModel({
        store: store,
        rootId: "root",
        rootLabel: "Customers",
        childrenAttrs: ["children"]
    });

Assuming that have an HTML div on our page with an id of “_treeHolder”, we can now create the tree and attach it to that empty div:

this._tree = new dijit.Tree({model: treeModel, showRoot: false}, dojo.byId("_treeHolder"));

The tree will now display successfully. With some items expanded, it looks like this:

Applying styles to the tree

There are many ways we can apply CSS styling to the tree. However, a category of advanced techniques involves overriding the tree class itself to add different CSS classes to different levels of the tree, therefore enabling different styles at different depths. We start out by altering the _restructureCustomerData function slightly to insert metadata about each object, specifically which CSS class we want to apply to each level in the tree:

 _restructureCustomerData = function(data) {
        var newData = dojo.map(data, dojo.hitch(this, function(customer) {
            var newCustomer = {};

            newCustomer.id = customer.customerNum;
            newCustomer.name = customer.name;
	    newCustomer.cssClass = "customer";

            newCustomer.children = dojo.map(customer.orders, dojo.hitch(this, function(idPrefix, order) {
		var newOrder = {};

		newOrder.id = idPrefix + "_" + order.orderNum;
		newOrder.name = order.orderNum;
	        newOrder.cssClass = "order";

		newOrder.children = dojo.map(order.items, dojo.hitch(this, function(idPrefix, item) {
		    var newItem = {};

		    newItem.id = idPrefix + "_" + item.itemNum;
		    newItem.name = item.description;
                    newItem.cssClass = "description";

		    return newItem;
		    }, newOrder.id));

		return newOrder;
		}, newCustomer.id));

            return newCustomer;
        }));

        return newData;
    }

We now extend the dijit.Tree class itself to create our own tree class, overriding the getRowClass() function. This allows us to assign a custom CSS class to each row, based on the data we’ve just inserted into the data store:

    dojo.declare("ibm.dijit.examples.LevelSensitiveTree", [ dijit.Tree ], {
	getRowClass: function(item, opened) {
	    if(item.id !== "root") {
		return this.model.store.getValue(item, "cssClass");
            }
	}
    });

We can then use this new tree class in the same way as the regular dijit.Tree class. The resultant tree looks like this:

In this article you have hopefully learnt some practical lessons on how to use and style Dojo trees based on raw data.

Tags: , , ,

Follow

Get every new post delivered to your Inbox.

Join 42 other followers