Monday, January 17, 2011

Dojo Dijit.Tree

Building a Javascript Object Explorer using the dojo Tree dijit.


Chapter 15 of Dojo: The Definitive Guide give a nice description of the Tree dijit using a TreeStoreModel or ItemFileReadStore.

Regarding the TreeStoreModel, Matthew Russell notes that "anything that presents this interface is just a valid model as the TreeStoreModel".


His comment give the answer to how one would build an object explorer.


The interface methods identified for readonly viewing are:

  • getRoot
  • mayHaveChildren
  • getChildren
  • getIdentity
  • getLabel


The interface was documented in the book but can also be found in the source code:

  • getRoot: function(onItem, onError)
  • mayHaveChildren: function(/*dojo.data.Item*/ item)
  • getChildren: function(/*dojo.data.Item*/ parentItem, /*function(items)*/ onComplete, /*function*/ onError)
  • getIdentity: function(/* item */ item)
  • getLabel: function(/*dojo.data.Item*/ item)


Armed with this information is was just a matter of writing the code:


var model = (function (args) {
    if (dojo.isString(args)) args = { root: args };
    args.root = args.root || "window";
    args.identifier = args.identifier || "id";
    args.label = args.label || "name";
    if (dojo.isString(args.root)) {
        var root = { parent: null };
        root[args.identifier] = args.root;
        root[args.label] = args.root;
        args.root = root;
    }
    if (!args.root.parent) {
        var parentPath = args.root[args.identifier].split(".");
        parentPath = parentPath.splice(0, parentPath.length - 1);
        parentPath = parentPath.join(".") || "dojo.global";
        args.root.parent = dojo.getObject(parentPath);
    }
    var result = {
        args: args,
        _getValue: function (item) {
            if (!item) return undefined;
            return dojo.getObject(item[args.identifier], false, args.root.parent);
        },
        getRoot: function (f1, f2) {
            f1(args.root);
        },
        mayHaveChildren: function (item) {
            var value = this._getValue(item);
            return dojo.isObject(value);
        },
        getIdentity: function (item) {
            return item[args.identifier];
        },
        getLabel: function (item) {
            return item[args.label];
        },
        getChildren: function (parentItem, callback) {
            var p = this._getValue(parentItem), children = [], itemName, child;
            for (itemName in p) {
                try {
                    child = { };
                    child[args.label] = itemName;
                    child[args.identifier] = parentItem[args.identifier] + '.' + itemName;
                    children.push(child);
                } catch (ex) {
                    console.log(ex);
                }
            }
            callback(children);
        }
    }
    return result;
} ("window"));

The args.identifier and args.label are in the interest of generality and don't add much value. Likewise _getValue requires the root parent and fully qualified identifiers. The alternative is to capture the value in the getChildren. Eliminate these features and the code is cut in half.


Links:
Nightly Build Tree Tests
Dojo Dictionary

No comments:

Post a Comment