I have a dijit.Tree backed by a ForestStoreModel that uses a custom data store to provide the data. It works well, but I want to provide the ability for the user to rearrange the top-level items (and only the top level) items via the dojo drag-and-drop facility.
The problem is the the ForestStoreModel::pasteItem function checks to see if item is a child of the root and then passes a null to the TreeStoreModel::pasteItem.
pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
// summary:
// Move or copy an item from one parent item to another.
// Used in drag & drop
if(oldParentItem === this.root){
if(!bCopy){
// It's onLeaveRoot()'s responsibility to modify the item so it no longer matches
// this.query... thus triggering an onChildrenChange() event to notify the Tree
// that this element is no longer a child of the root node
this.onLeaveRoot(childItem);
}
}
dijit.tree.TreeStoreModel.prototype.pasteItem.call(this, childItem,
oldParentItem === this.root ? null : oldParentItem,
newParentItem === this.root ? null : newParentItem,
bCopy,
insertIndex
);
if(newParentItem === this.root){
// It's onAddToRoot()'s responsibility to modify the item so it matches
// this.query... thus triggering an onChildrenChange() event to notify the Tree
// that this element is now a child of the root node
this.onAddToRoot(childItem);
}
}
The TreeStoreModel does not update the underlying data store if the passed parent items are null and the onLeaveRoot and onAddToRoot events do not pass in the insertIndex, so I cannot use them to update my data store (which seems like it would be a bit backwards, anyway).
At this point I think the only viable option is to extend the ForestStoreModel in order to allow me to set the synthetic $root$ item to a compatible data store object and allow the ForestStoreModel to pass it, unaltered, through to the TreeStoreModel.
Are there other way of approaching this problem?
Update
The eventual solution turned out to be even simpler than suggested. My ForestStoreModel is already a custom class because I am actually using the dojo 1.6 ObjectStore as a data source, so I can pass the desired index in the options argument to the object store put method. The fix was just a one-liner as I let the parent class take care of calling onLeaveRoot and onAddRoot:
pasteItem: function(/*Item*/ childItem, /*Item*/ oldParentItem, /*Item*/ newParentItem, /*Boolean*/ bCopy, /*int?*/ insertIndex){
// Handle drag & drop at the root level
if (oldParentItem === this.root && newParentItem === this.root){
this.store.put(childItem, { index: insertIndex });
}
this.inherited(arguments);
}
You will need to subclass
ForestTreeModel, you can’t escape that. But, you’ll only need to overridepasteItem. You can’t pass the synthetic root to theTreeStoreModelbecause it doesn’t know anything about it.If you need to modify the underlying data store, you’re better off calling
this.store.setValues()directly. That should trigger theonSetItemevent and in turn call_requeryTop()for you, which will fetch the roots from the underlying store in whatever order you arrange them, so be sure to reflect that in your modification.The other, easier way, is to manipulate
this.root.childrenyourself and then emit the eventonChildrenChangeto notify the views. Beware, that method won’t persist the order.