Opened 9 years ago

Closed 9 years ago

#11304 closed enhancement (fixed)

Tree: make set("path", ...) return a dojo Deferred

Reported by: Simon Speich Owned by: bill
Priority: high Milestone: 1.5
Component: Dijit Version: 1.5.0b2
Keywords: dijit tree deferred path Cc:
Blocked By: Blocking:

Description

Since setting the tree to a certain path might be asynchronous depending on the store, it would be helpful if the method returned a dojo deferred e.g:

var d = tree.attr('path', myPath);
d.addCallback(function{
  // do something when children are loaded
});

I tried to add this myself in tree.js in the _setPathAttr method. by changing line 843:

this._expandNode(node).addCallback(dojo.hitch(this, advance));

to

return this._expandNode(node).addCallback(dojo.hitch(this, advance));

since this._expandNode returns a deferred. But what about returning this._loadDeferred from line 801?

Change History (6)

comment:1 Changed 9 years ago by James Burke

Component: GeneralDijit
Owner: anonymous deleted

comment:2 Changed 9 years ago by Simon Speich

I think I have a working patch:

_setPathAttr: function(/*Item[] || String[]*/ path){
		// summary:
		//		Select the tree node identified by passed path. Overrides the
		//    dojo.tree method to return a dojo.deferred
		// path:
		//		Array of items or item id's
		// return:
		//    dojo.Deferred

		if(!path || !path.length){ return; }

		// If this is called during initialization, defer running until Tree has finished loading
		this._loadDeferred.addCallback(dojo.hitch(this, function(){
			if(!this.rootNode){
				console.debug("!this.rootNode");
				return;
			}
			if(path[0] !== this.rootNode.item && (dojo.isString(path[0]) && path[0] != this.model.getIdentity(this.rootNode.item))){
				console.error(this, ":path[0] doesn't match this.rootNode.item.  Maybe you are using the wrong tree.");
				return;
			}
			path.shift();

			var node = this.rootNode;

			function advance(){
				// summary:
				// 		Called when "node" has completed loading and expanding.   Pop the next item from the path
				//		(which must be a child of "node") and advance to it, and then recurse.

				// Set item and identity to next item in path (node is pointing to the item that was popped
				// from the path _last_ time.
				var item = path.shift(),
					identity = dojo.isString(item) ? item : this.model.getIdentity(item);

				// Change "node" from previous item in path to the item we just popped from path
				dojo.some(this._itemNodesMap[identity], function(n){
					if(n.getParent() == node){
						node = n;
						return true;
					}
					return false;
				});

				if(path.length){
					// Need to do more expanding
					var def = this._expandNode(node);
					def.addCallback(dojo.hitch(this, advance));
					return def;
				}else{
					// Final destination node, select it
					if(this.lastFocused != node){
						this.focusNode(node);
					}
				}
			}
			var def = this._expandNode(node);
			def.addCallback(dojo.hitch(this, advance));
			return def;
		}));
		return this._loadDeferred;
	}

comment:3 Changed 9 years ago by bill

Milestone: tbd1.6

this._loadDeferred fires as soon as the Tree itself has finished loading. It doesn't wait for the set('path', ...) call to finish. If set('path', ...) is a deep path there will many Deferred objects created sequentially, one for each level in the path that isn't already loaded, and only when the last one completes should the set() operation be considered complete.

I think that _setPathAttr() just needs to create and return a new Deferred object, and then fire it when the

}else{
	// Final destination node, select it
	this._selectNode(node);
}

code block runs.

comment:4 Changed 9 years ago by Simon Speich

Thank you for the explanation. You were absolutely right. It is enough to just add:

var def = new dojo.Deferred(); // added to the first line:
...
}else{
	// Final destination node, select it
	this._selectNode(node);
	def.callback(true); // added
}
...
return def; // added to the last line

and the following works now:

var d = tree.attr('path', myPath);
d.addCallback(function{
  // do something when children are loaded
});

comment:5 Changed 9 years ago by bill

Milestone: 1.61.5
Owner: set to bill
Status: newassigned
Summary: Using tree.attr('path', myPath) should return a dojo DeferredTree: make set("path", ...) return a dojo Deferred

OK, might as well add it to 1.5.

comment:6 Changed 9 years ago by bill

Resolution: fixed
Status: assignedclosed

(In [22425]) Make set("path", ...) return a Deferred to indicate when the set is complete, fixes #11304 !strict.

Note: See TracTickets for help on using tickets.