Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
218 views
in Technique[技术] by (71.8m points)

dojo - Moving nodes within a Dijit Tree

I am using a tree as an input tool to allow the user to organize categories.

I would like the users to be able to move the nodes around at the top level, specifically reordering them under the same parent.

Everything looks fine until it is time for the store to be updated - the display is wrong - the moved item is not shown in the right place.

require([
  "dojo/aspect",
  "dojo/store/Memory",
  "dojo/store/Observable",
  "dijit/Tree",
  "dijit/tree/ObjectStoreModel",
  "dijit/tree/dndSource",
  "dojo/domReady!"
], function(aspect, Memory, Observable, Tree, ObjectStoreModel, dndSource) {

  var observableStore, model;
  var memoryStore = new Memory({
    data: [{
      "id": 10,
      "position": 0,
      "name": "top",
      "parent": null
    }, {
      "id": 19,
      "position": 18,
      "name": "Audio",
      "parent": 10
    }, {
      "id": 23,
      "position": 19,
      "name": "Monitors",
      "parent": 10
    }, {
      "id": 20,
      "position": 20,
      "name": "Communication",
      "parent": 10
    }, {
      "id": 21,
      "position": 28,
      "name": "Video",
      "parent": 10
    }, {
      "id": 18,
      "position": 29,
      "name": "Camera",
      "parent": 10
    }, {
      "id": 22,
      "position": 40,
      "name": "Five",
      "parent": 21
    }, {
      "id": 24,
      "position": 60,
      "name": "Networking",
      "parent": 21
    }, {
      "id": 25,
      "position": 70,
      "name": "Toasters",
      "parent": 18
    }],
    mayHaveChildren: function(object) {
      var children = this.store.getChildren(object);
      return children.length > 0;
    },
                    getChildren: function (object) {
                    return this.query({parent: object.id});
                }
  });

  observableStore = new Observable(memoryStore);

  model = new ObjectStoreModel({
    store: observableStore,
    query: {
      name: "top"
    }
  });

  aspect.around(memoryStore, "put", function(originalPut) {
    // To support DnD, the store must support put(child, {parent: parent}).
    // Since memory store doesn't, we hack it.
    // Since our store is relational, that just amounts to setting child.parent
    // to the parent's id.
    return function(obj, options) {
      if (options && options.parent) {
        obj.parent = options.parent.id;
      }
      return originalPut.call(memoryStore, obj, options);
    }
  });

  var tree =new Tree({
    model: model,
    dndController: dndSource,
    betweenThreshold: 5,
    showRoot: false,
    persist: false
  }, "category-tree").startup();


});

JSFiddle

https://bugs.dojotoolkit.org/ticket/18142 - I could invest more time in this, but I don't want to. Choosing a different approach - using traditional inputs and providing a read-only tree view.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to place the aspect around the store's put function before wrapping it with Observable. With your code Observable hasn't got access to the replaced put function. It will work if you replicate closely the example.

require([
  "dojo/aspect",
  "dojo/store/Memory",
  "dojo/store/Observable",
  "dijit/Tree",
  "dijit/tree/ObjectStoreModel",
  "dijit/tree/dndSource",
  "dojo/domReady!"
], function(aspect, Memory, Observable, Tree, ObjectStoreModel, dndSource) {

  var observableStore, model;
  var memoryStore = new Memory({
    data: [{
      "id": 10,
      "position": 0,
      "name": "top",
      "parent": null
    }, {
      "id": 19,
      "position": 18,
      "name": "Audio",
      "parent": 10
    }, {
      "id": 23,
      "position": 19,
      "name": "Monitors",
      "parent": 10
    }, {
      "id": 20,
      "position": 20,
      "name": "Communication",
      "parent": 10
    }, {
      "id": 21,
      "position": 28,
      "name": "Video",
      "parent": 10
    }, {
      "id": 18,
      "position": 29,
      "name": "Camera",
      "parent": 10
    }, {
      "id": 22,
      "position": 40,
      "name": "Five",
      "parent": 21
    }, {
      "id": 24,
      "position": 60,
      "name": "Networking",
      "parent": 21
    }, {
      "id": 25,
      "position": 70,
      "name": "Toasters",
      "parent": 18
    }],
    mayHaveChildren: function(object) {
      var children = this.store.getChildren(object);
      return children.length > 0;
    },
                    getChildren: function (object) {
                    return this.query({parent: object.id});
                }
  });

  aspect.around(memoryStore, "put", function(originalPut) {
    // To support DnD, the store must support put(child, {parent: parent}).
    // Since memory store doesn't, we hack it.
    // Since our store is relational, that just amounts to setting child.parent
    // to the parent's id.
    return function(obj, options) {
      if (options && options.parent) {
        obj.parent = options.parent.id;
      }
      return originalPut.call(memoryStore, obj, options);
    }
  });

  observableStore = new Observable(memoryStore);

  model = new ObjectStoreModel({
    store: observableStore,
    query: {
      name: "top"
    }
  });


  var tree =new Tree({
    model: model,
    dndController: dndSource,
    showRoot: false,
    persist: false
  }, "category-tree").startup();


});

A fork of your JSFiddle.

UPDATE: The above solution does not support the betweenThreshold option (the ability to drop an item in between others instead of making it a child of another item). Even the official reference guide example does not work. This needs a store that properly supports positioning of items (MemoryStore doesn't and the hack for the put function is not enough). One option is to fall back on the deprecated dojo/data/ItemFileWriteStore.

require([
  "dojo/data/ItemFileWriteStore",
  "dijit/Tree",
  "dijit/tree/TreeStoreModel",
  "dijit/tree/dndSource",
  "dojo/domReady!"
], function(ItemFileWriteStore, Tree, TreeStoreModel, dndSource) {

  var model;

  var categories = {
    identifier: 'id',
    label: 'name',
    items: [
        { id: '0', name:'Foods', numberOfItems:1, children:[ {_reference: '1'},  {_reference: '2'},  {_reference: '3'} ] },
            { id: '1', name:'Fruits', numberOfItems:1, children:[ {_reference: '4'} ] },
                { id: '4',name:'Citrus', numberOfItems:1, items:[ {_reference: '5'} ] },
                    { id: '5', name:'Orange'},
        { id: '2', name:'Vegetables', numberOfItems:0},
        { id: '3', name:'Cereals', numberOfItems:0}
    ]
};
  var memoryStore = new ItemFileWriteStore({data: categories});

  var model = new TreeStoreModel({store: memoryStore, query:{id: "0"}});


  var tree =new Tree({
    model: model,
    dndController: dndSource,
    betweenThreshold: 5,
    showRoot: false,
    persist: false
  }, "category-tree").startup();


});

Here is another JSFiddle. You can also refer to this example.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...