Reputation: 8133
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);
}
Upvotes: 2
Views: 1861
Reputation: 2690
You will need to subclass ForestTreeModel
, you can't escape that. But, you'll only need to override pasteItem
. You can't pass the synthetic root to the TreeStoreModel
because 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 the onSetItem
event 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.
dojo.declare('MyForestTreeModel', [ dijit.tree.ForestTreeModel ], {
pasteItem: function(childItem, oldParentItem, newParentItem, bCopy, insertIndex) {
if (oldParentItem == this.root && newParentItem == this.root) {
if (!bCopy) { this.onLeaveRoot(childItem); }
// modify the underlying store somehow so the call to _requeryTop() fetches
// the items in the correct order.
// (you decide what's 'order' and what new_order() returns)
this.store.setValues(childItem, 'order', new_order(insertIndex));
this.onAddRoot(childItem);
} else {
// call super
this.inherited(arguments);
}
}
});
The other, easier way, is to manipulate this.root.children
yourself and then emit the event onChildrenChange
to notify the views. Beware, that method won't persist the order.
dojo.declare('MyForestTreeModel', [ dijit.tree.ForestTreeModel ], {
pasteItem: function(childItem, oldParentItem, newParentItem, bCopy, insertIndex) {
if (oldParentItem == this.root && newParentItem == this.root) {
if (!bCopy) { this.onLeaveRoot(childItem); }
// manipulate this.root.children to reorder childItem
// remove child from the current position
var children = dojo.filter(this.root.children, function(x) {
return x != childItem;
});
// and insert it into the new index
children.splice(insertIndex, 0, childItem);
this.root.children = children;
// notify views
this.onChildrenChanged(this.root, children);
this.onAddRoot(childItem);
} else {
// call super
this.inherited(arguments);
}
}
});
Upvotes: 1