treedojostoredijit.tree

Dijit Tree filtering and search not working on ObjectStoreModel


I have created a dijit tree and a textbox and I want to filter the tree nodes based on keywords provided in textbox. I implemented the solution provided in another question but it does not seem to work. When the user enter some word in textbox the tree is re-populated with same data.

dijit.Tree search and refresh

Following is my code:

require(["dijit/form/TextBox","dojo/store/Memory","dijit/tree/ObjectStoreModel","dijit/Tree","dojo/domReady!"],     function(TextBox, MemoryStore, ObjectStoreModel, Tree) {

var searchBox = new TextBox({
    placeHolder: "[  Type here to search  ]"
}, "searchBox");

searchBox.on("blur", function() {
    tree.model.store.query({
        name: "*" + searchBox.value + "*"
    });

 /*the below approach has been taken from the other question*/
    tree.model.store.clearOnClose = true;
    /*tree.model.store.close(); //This is not working?*/
    delete tree._itemNodesMap;
    tree._itemNodesMap = {};
    tree.rootNode.state = "UNCHECKED";
    delete tree.model.root.children;
    tree.model.root.children = null;
    tree.rootNode.destroyRecursive();
    tree.model.constructor(tree.model)
    tree.postMixInProperties();
    tree._load();

});

var store = new MemoryStore({
    idProperty: "id",
    getChildren: function(object) {
        return this.query({
            parent: object.id
        });
    },
    data: [{
        id: "0",
        name: "Root Node",
        parent: null
    }, {
        id: "1",
        name: "File",
        parent: "0"
    }, {
        id: "2",
        name: "System",
        parent: "0"
    }, {
        id: "3",
        name: "Diagnosis",
        parent: "0"
    }, {
        id: "4",
        name: "Management",
        parent: "0"
    }]
});

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

var tree = new Tree({
    model: model,
    showRoot: false
}, "treeDiv");

tree.startup();

});

See the example code at JSFIDDLE: http://jsfiddle.net/xLfdhnrf/16/

The tree and textbox is rendering fine only search is not working, any suggestions? Also why the EXPAND (+) sign is showing with leaf nodes?

Snapshot of Filterable Tree


Solution

  • I have added a custom property to the data of model. It is named keep and it is in charge of the filtering. Each item of the data have this property. If keep is true the item will be visible. if keep is false the item will be hidden.
    When the input blurs, keep is updated and the tree is re-created.
    In order to keep the tree structure, if an item is matching the text, we recursively mark all it's parent as keep, even if they are not matching (otherwise you would not see the item itself)
    I commented some unneeded lines for the tree re-creation.

    As you can see, the keep is used in

        getChildren: function(object) {
            return this.query({
                parent: object.id,
                keep: true
            });
        },
    

    This is how the tree get filtered.

    I have created a method mayHaveChildren in the model. If this method return true you have an expandable node. If it returns false you have a normal node. See http://dojotoolkit.org/reference-guide/1.10/dijit/tree/Model.html for details.
    mayHaveChildren return value is based on a store query.

    Finally, I used regular expression instead of plain string so the match is case insensitive.

    require(["dijit/form/TextBox", "dojo/store/Memory", "dijit/tree/ObjectStoreModel", "dijit/Tree", "dojo/domReady!"], function(TextBox, MemoryStore, ObjectStoreModel, Tree) {
        var searchBox = new TextBox({
            placeHolder: "[  Type here to search  ]"
        }, "searchBox");
        searchBox.on("blur", function() {
            var includeParent = function(itemId) {
              tree.model.store.query({
                id: itemId
              }).forEach(function(item) {
                item.keep = true;
                //and we include all parent tree
                includeParent(item.parent);
            });
            }
          
            //reset all node, first we exlude them all
            tree.model.store.query().forEach(function(item) {
              item.keep = false;
            });
            //then we include only the one matching
            tree.model.store.query({
               name: new RegExp('.*' + searchBox.value + '.*', 'i')
            }).forEach(function(item) {
              item.keep = true;
              //and we include all parent tree
              includeParent(item.parent);
            });
            
    
            //delete tree._itemNodesMap;
            //tree._itemNodesMap = {};
            //tree.rootNode.state = "UNCHECKED";
            //delete tree.model.root.children;
            //tree.model.root.children = null;
            tree.rootNode.destroyRecursive();
            tree.model.constructor(tree.model)
            tree.postMixInProperties();
            tree._load();
        });
    
        var store = new MemoryStore({
            idProperty: "id",
            getChildren: function(object) {
                return this.query({
                    parent: object.id,
                    keep: true
                });
            },
            data: [{
                id: "0",
                name: "Root Node",
                parent: null,
                keep: true
            }, {
                id: "1",
                name: "File",
                parent: "0",
                keep: true
            }, {
                id: "2",
                name: "System",
                parent: "0",
                keep: true
            }, {
                id: "3",
                name: "Diagnosis",
                parent: "0",
                keep: true
            }, {
                id: "4",
                name: "Management",
                parent: "0",
                keep: true
            },
            {
                id: "5",
                name: "New",
                parent: "1",
                keep: true
            },
            {
                id: "6",
                name: "Open",
                parent: "1",
                keep: true
            },
            {
                id: "7",
                name: "Import",
                parent: "1",
                keep: true
            }]
        });
    
        var model = new ObjectStoreModel({
            store: store,
            query: {
                id: "0"
            },
            mayHaveChildren: function (item) { return store.query({parent: item.id}).length > 0; }
        });
    
        var tree = new Tree({
            model: model,
            showRoot: false
        }, "treeDiv");
    
        tree.startup();
    
    });
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
    <link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dijit/themes/claro/claro.css">
    
    
    <body class="claro">
    <div id="searchBox"></div>
    <div id="treeDiv"></div>        
    </div>