2

In one of my projects I use a dijit.Tree control. I need to add a search to the tree and show only those nodes/leafs which have the searched term in them. However I can't seem to figure out how that can be achieved. Could anybody please help me?

DanMan
  • 11,323
  • 4
  • 40
  • 61
cycero
  • 4,547
  • 20
  • 53
  • 78

1 Answers1

0

im not entirely sure that your question entirely but it should give hint whereas to go.

Lets use reference documentation example as offset, there is 1) a store 2) a model and 3) the tree

    var store = new ItemFileReadStore({
        url: "{{dataUrl}}/dijit/tests/_data/countries.json"
    });

    var treeModel = new ForestStoreModel({
        store: store,
        query: {"type": "continent"}, // note, this bit
        rootId: "root",
        rootLabel: "Continents",
        childrenAttrs: ["children"]
    });

    new Tree({
        model: treeModel
    }, "treeOne");

Interpret the above as such; You have loaded all known countries and continents but 'user' has selected only to show continents by using query on the model - and the hierachy is then represented in a tree structure.

You want a textbox with searching capeabilities, so we hook into onChange

    new dijit.form.TextBox({
        onChange: function() {
              ...
        }
    });

First bit, getting variables

var searchByName = this.get("value");
var oQuery = treeModel.query;

Next, set a new query on the model - preserving the old ones with an object mixin

treeModel.query = dojo.mixin(oQuery, { name: '*'+searchByName+'*' });

Last, notify the model and its tree that changes has occurred - and requery the visible items.

treeModel._requeryTop();

NB If the top-level item (for ForestModel) is not visible, none of its child elements will show, even if the search-string matches those. (Examplewise, Alabama is not shown if US Continent is not matched by query)

EDIT

As OP has the agenda to go by the 'NB', this may not fit needs 100% but its what dojo offers with dijit.Tree.. As it will get rather a lengthy process to recode the model/store queries to include parentbranches up until root i will not do this here - but there are a few tricks still ;)

var tree = new dijit.Tree( {
   /**
    * Since TreeNode has a getParent() method, this abstraction could be useful
    * It sets the dijit.reqistry id into the item-data, so one l8r can get parent items
    * which otherwise only can be found by iterating everything in store, looking for item in the parent.children
    *
   */
   onLoad : function() {
       this.forAllNodes(function(node) {
            // TreeNode.item <-- > store.items hookup
            node.item._NID = node.domNode.id
       });
   },
   /* recursive iteration over TreeNode's
    * Carefull, not to make (too many) recursive calls in the callback function..
    * fun_ptr : function(TreeNode) { ... }
   */
   forAllNodes : function(parentTreeNode, fun_ptr) {
        parentTreeNode.getChildren().forEach(function(n) {
             fun_ptr(n);
             if(n.item.children) {
                 n.tree.forAllNodes(fun_ptr);
             }
        })
   }
});

(non-tested, but might just work) Example:

// var 'tree' is your tree, extended with
tree.forAllNodes = function(parentTreeNode, fun_ptr) {
        parentTreeNode.getChildren().forEach(function(n) {
             fun_ptr(n);
             if(n.item.children) {
                 n.tree.forAllNodes(fun_ptr);
             }
        })
};
// before anything, but the 'match-all' query, run this once
tree.forAllNodes(tree.rootNode, function(node) {
    // TreeNode.item <-- > store.items hookup
    node.item._NID = node.domNode.id
});

// hopefully, this in end contains top-level items
var branchesToShow = [] 

// run fetch every search (TextBox.onChange) with value in query
tree.model.store.fetch(query:{name:'Abc*'}, onComplete(function(items) {
   var TreeNode = null;
   dojo.forEach(items, function(item) {
       TreeNode = dijit.byId(item._NID+'');
       while(TreeNode.getParent() 
             && typeof TreeNode.getParent().item._RI == 'undefined') {
          TreeNode = TreeNode.getParent();
       }
       branchesToShow.push(TreeNode.item);
   });
}});

// Now... If a success, try updating the model via following
tree.model.onChildrenChange(tree.model.root, branchesToShow);
mschr
  • 8,531
  • 3
  • 21
  • 35
  • Hello and thanks for your help! The case is that in my original definition of the tree model I have "query: {"type": "parent"}" while when searching I need to get the query based on the name of both nodes and leafs. In this current case it does not return any nodes when I search by the name of a leaf. – cycero Jul 24 '12 at 12:14
  • the store query itself will return results.. only, the tree cannot show them since their the branch of a leaf has been 'cut off', i.e. higher level item values does not match query. you would need to query the store and then manually iterate children nodes to set a full branch visible/hidden – mschr Jul 24 '12 at 15:08
  • it will get rather messy... model does not doubly-link the items so children doesnt know who their parents are – mschr Jul 24 '12 at 15:20
  • So, it's basically impossible? – cycero Jul 24 '12 at 15:22
  • nothing is impossible :p but that being said I would suggest setting up a FilteringSelect input field, using the same store - other then spending 3-4 hours plus coding that implementation. Or make `store.fetch({query:{namebasedonly:'??'}, onComplete:function(items) { items...ids...tree...nodes..toggle highlight CSS if item match } });` functionality – mschr Jul 24 '12 at 15:28
  • take another look, it may or may not run – mschr Jul 24 '12 at 16:01