I originally posted this on the Sencha forums here but didn\'t get any responses (other than my own answer, which I will post soon), so I am going to repost it here and see
I was looking for a way to filter a treestore so that if a filterBy function returned true for any node, I wanted to display the complete node hierarchy of that node including all the parent nodes, grand parent node, etc and child nodes, grand child node, etc. I modified it from the other solutions provided in this question. This solutions works recursively so the treestore can be of any size.
Ext.override(Ext.data.TreeStore, {
hasFilter: false,
/**
* Filters the current tree by a function fn
* if the function returns true the node will be in the filtered tree
* a filtered tree has also a flat structure without folders
*/
filterBy : function(fn, scope) {
var me = this,
nodes = [],
root = me.getRootNode(),
tmp;
// the snapshot holds a copy of the current unfiltered tree
me.snapshot = me.snapshot || root.copy(null, true);
tmp = me.snapshot.copy(null, true);
var childNodes = tmp.childNodes;
root.removeAll();
for( var i=0; i < childNodes.length; i++ ) {
//Recursively tranverse through the root and adds the childNodes[i] if fn returns true
if( this.traverseNode( childNodes[i], root, fn ) == true ) {
i--;
}
}
return me;
},
/**
* Recursively tranverse through the root and adds the childNodes[i] if fn returns true
*/
traverseNode: function( node, parentNode, fn ) {
var me = this;
if( fn.call( me, node ) ) {
parentNode.appendChild( node );
return true;
}
if( node.hasChildNodes() ) {
var childNodes = node.childNodes;
var found = false;
for( var i=0; i < childNodes.length; i++ ) {
if( this.traverseNode( childNodes[i], node, fn ) == true ) {
found = true;
}
}
if( found == true ) {
parentNode.appendChild( node );
return true;
}
}
return false;
},
/**
* Clears all filters a shows the unfiltered tree
*/
clearFilter : function() {
var me = this;
if (me.isFiltered()) {
me.setRootNode(me.snapshot);
delete me.snapshot;
}
return me;
},
/**
* Returns true if the tree is filtered
*/
isFiltered : function() {
return !!this.snapshot;
}
});
So it works with just like a regular store filterBy call.
searchText = "searchText";
store.filterBy( function(item) {
var keys = item.fields.keys;
for( var i=0; i < keys.length; i++ ) {
var value = item.get( keys[i] );
if( value != null ) {
if( value.toString().toLowerCase().indexOf( searchText ) !== -1 ) {
return true;
}
}
}
return false;
});