如何通过拖放操作在dijit树中安排顶级节点项

时间:2011-08-03 20:01:27

标签: drag-and-drop tree dojo

我有一个由dijit.Tree支持的ForestStoreModel,它使用自定义数据存储来提供数据。它运行良好,但我想让用户能够通过dojo拖放工具重新排列顶级项目(并且只有顶层)项目。

问题是ForestStoreModel::pasteItem函数检查项是否是根的子项,然后将null传递给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);
        }
    }

如果传递的父项为空并且TreeStoreModelonLeaveRoot事件未在onAddToRoot中传递,则insertIndex不会更新基础数据存储,所以我不能使用它们来更新我的数据存储(无论如何它似乎有点倒退)。

此时我认为唯一可行的选择是扩展ForestStoreModel以便允许我将合成$root$项设置为兼容的数据存储对象并允许ForestStoreModel不加改变地传递给TreeStoreModel

还有其他方法可以解决这个问题吗?

更新

最终的解决方案比建议的更简单。我的ForestStoreModel已经是一个自定义类,因为我实际上使用dojo 1.6 ObjectStore作为数据源,所以我可以将options参数中的所需索引传递给对象库put方法。修复只是一个单行,因为我让父类负责调用onLeaveRootonAddRoot

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);
}

1 个答案:

答案 0 :(得分:1)

你需要继承ForestTreeModel,你无法逃脱。但是,您只需要覆盖pasteItem。您无法将合成根传递给TreeStoreModel,因为它对此一无所知。

如果您需要修改基础数据存储,最好直接调用this.store.setValues()。这应该触发onSetItem事件,然后为你调用_requeryTop(),它将按照你安排它们的顺序从底层商店获取根,所以一定要在你的修改中反映出来。

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);
    }
  }
});

另一种更简单的方法是自己操纵this.root.children,然后发出事件onChildrenChange以通知视图。请注意,该方法不会保留订单。

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);
    }
  }
});