dijit.Tree search and refresh

4.3k views Asked by At

I can't seem to figure out how to search in a dijit.Tree, using a ItemFileWriteStore and a TreeStoreModel. Everything is declarative, I am using Dojo 1.7.1, here is what I have so far :

<input type="text" dojoType="dijit.form.TextBox" name="search_fruit" id="search_fruit" onclick="search_fruit();">
<!-- store -->
<div data-dojo-id="fruitsStore" data-dojo-type="dojo.data.ItemFileWriteStore" clearOnClose="true" urlPreventCache="true" data-dojo-props='url:"fruits_store.php"'></div>
<!-- model -->
<div data-dojo-id="fruitsModel" data-dojo-type="dijit.tree.TreeStoreModel" data-dojo-props="store:fruitsStore, query:{}"></div>
<!-- tree -->
<div id="fruitsTree" data-dojo-type="dijit.Tree"
     data-dojo-props='"class":"container",
     model:fruitsModel,
     dndController:"dijit.tree.dndSource",
     betweenThreshold:5,
     persist:true'>
</div>

The json returned by fruits_store.php is like this :

{"identifier":"id",
 "label":"name",
 "items":[{"id":"OYAHQIBVbeORMfBNZXFGOHPdaRMNUdWEDRPASHSVDBSKALKIcBZQ","name":"Fruits","children":[{"id":"bSKSVDdRMRfEFNccfTZbWHSACWbLJZMTNHDVVcYGcTBDcIdKIfYQ","name":"Banana"},{"id":"JYDeLNIGPDBRMcfSTMeERZZEUUIOMNEYYcNCaCQbCMIWOMQdMEZA","name":"Citrus","children":[{"id":"KdDUfEDaKOQMFNJaYbSbAcAPFBBdLALFMIPTFaYSeCaDOFaEPbJQ","name":"Orange"},{"id":"SDWbXWbTWKNJDIfdAdJbbbRWcLZFJHdEWASYDCeFOZYdcZUXJEUQ","name":"Lemon"}]},{"id":"fUdQTEZaIeBIWCHMeBZbPdEWWIQBFbVDbNFfJXNILYeBLbWUFYeQ","name":"Common ","children":[{"id":"MBeIUKReBHbFWPDFACFGWPePcNANPVdQLBBXYaTPRXXcTYRTJLDQ","name":"Apple"}]}]}]}

Using a grid instead of a tree, my search_fruit() function would look like this :

function search_fruit() {
  var grid = dijit.byId('grid_fruits');
  grid.query.search_txt = dijit.byId('search_fruit').get('value');
  grid.selection.clear();
  grid.store.close();
  grid._refresh();
}

How to achieve the same using the tree ? Thanks !

1

There are 1 answers

0
mschr On

The refreshing of a dijit.Tree becomes a little more complicated, since there is a model involved (which in grid afaik is inbuilt, the grid component implements query functionality)

Performing search via store

But how to search, thats incredibly easy whilst using the ItemFileReadStore. Syntax is as such:

myTree.model.store.fetch({
   query: {
      name: 'Oranges'
   },
   onComplete: function(items) { 
     dojo.forEach(items, function(item) { 
        console.log(myTree.model.store.getValue(item, "ID"));
     });
   }
});

Displaying search results only

As shown above, the store will fetch, the full payload is put into its _allItemsArray and the store queryengine then filters out what its told by query argument to the fetch method. At any time, we could call fetch on store, even without sending an XHR for json contents - fetch with query argument can be considered as a simple filter.

It becomes slightly more interesting to let the Model know about this query.. If you do so, it will only create treeNodes to fill the tree, based on the returned results from store.fetch({query:model.query});

So, instead of sending store.fetch with a callback, lets _try to set model query and update the tree.

// seing as we are working with a multi-parent tree model (ForestTree), the query Must match a toplevel item or else nothing is shown
myTree.model.query = { name:'Fruits' };
// below method must be implemented to do so runtime
// and note, that the DnD might become invalid
myTree.update(); 

Refreshing tree with new xhr-request from store

You need to do exactly as you do with regards to the store. Close it but then rebuild the model. Model contains all the TreeNodes (beneath its root-node) and the Tree itself maps an itemarray which needs to be cleared to avoid memory leakage.

So, performing following steps will rebuild the tree - however this sample does not take in account, if you have DnD activated, the dndSource/dndContainer will still reference the old DOM and thereby 'keep-alive' the previous DOMNode hierachy (hidden ofc).

By telling the model that its rootNode is UNCHECKED, the children of it will be checked for changes. This in turn will produce the subhierachy once the tree has done its _load()

Close the store (So that the store will do a new fetch()).

  this.model.store.clearOnClose = true;
  this.model.store.close();

Completely delete every node from the dijit.Tree

  delete this._itemNodesMap;
  this._itemNodesMap = {};
  this.rootNode.state = "UNCHECKED";
  delete this.model.root.children;
  this.model.root.children = null;

Destroy the widget

  this.rootNode.destroyRecursive();

Recreate the model, (with the model again)

  this.model.constructor(this.model)

Rebuild the tree

  this.postMixInProperties();
  this._load();

Creds; All together as such, scoped onto the dijit.Tree:

new dijit.Tree({

    // arguments
    ...
    // And additional functionality
    update : function() {
      this.model.store.clearOnClose = true;
      this.model.store.close();
      delete this._itemNodesMap;
      this._itemNodesMap = {};
      this.rootNode.state = "UNCHECKED";
      delete this.model.root.children;
      this.model.root.children = null;
      this.rootNode.destroyRecursive();
      this.model.constructor(this.model)
      this.postMixInProperties();
      this._load();
    }
});