PDA

View Full Version : treestore filter (ext-4.0.7-gpl)



Richie1985
11 Nov 2011, 4:28 AM
Hi,

i want to add a searchfield to my treepanel. In my treepanel is a long list of names. i want to filter by this names. i found something like that:


tbar : ['Filter:', {
xtype : 'trigger',
anchor : '-20',
triggerClass : 'x-form-clear-trigger',
onTriggerClick : function() {
this.setValue('');
tree.store.filters.clear();
},
id : 'filter',
enableKeyEvents : true,
listeners : {
keyup : {
buffer : 150,
fn : function(field, e) {
if (Ext.EventObject.ESC == e.getKey()) {
field.onTriggerClick();
} else {
var val = this.getRawValue();
var re = new RegExp('.*' + val + '.*', 'i');
console.log(tree);
console.log(val);
console.log(store.filters.filter);
store.filters.clear();
store.filters.filter(re, 'fullname');
}
}
}
}
}],


But nothing happens and no Error appears.

Can you help me?

Thx!

mankz
11 Nov 2011, 4:31 AM
TreeStore filtering is not supported in 4.0.x. I'd advice you to request this feature in the feature request forum (I'd love that feature as well) :).

tvanzoelen
11 Nov 2011, 4:35 AM
I use this http://www.sencha.com/forum/showthread.php?147941-TreeFilter

and it works fine.


complete code



treefilter = {

searchTree: function(tree, searchfield) {

if (tree && searchfield) {

tree.collapseAll();
//this call probably not needed
this.setNodesVisible(tree, tree.getRootNode());

if (searchfield.getRawValue().length > 1) {
this.searchTreeNode(tree, tree.getRootNode(), searchfield.getRawValue());
}
}

},

searchTreeNode: function(tree, node, query) {

for (var i = 0; i < node.childNodes.length; i++) {
this.searchTreeNode(tree, node.childNodes[i], query);
}

if (this.treeNodeMatch(node, query) == true) {
tree.expandPath(node.getPath());

this.setNodesVisible(tree, node);
}
else {
if (node.isExpanded() == false) {
this.setNodeVisible(tree, node, false);
}
}
},

treeNodeMatch: function(node, query) {
var re = new RegExp(query, "ig");

if (re.test(node.data.text) == true) {
return true;
}
else {
return false;
}
},

setNodesVisible: function(tree, node) {

for (var i = 0; i < node.childNodes.length; i++) {
this.setNodesVisible(tree, node.childNodes[i]);
}

this.setNodeVisible(tree, node, true);

},

setNodeVisible: function(tree, node, visible) {

var record = tree.getStore().getNodeById(node.internalId);
var viewNode = Ext.fly(tree.getView().getNode(record));

if (viewNode) {

viewNode.setVisibilityMode(Ext.Element.DISPLAY);

if (visible == true) {
viewNode.show();
}
else {
viewNode.hide();
}
}
}

}

Richie1985
11 Nov 2011, 4:47 AM
sounds great! and how do i implement this?

tvanzoelen
11 Nov 2011, 4:53 AM
you make that treefilter available somewhere and call searchTree on it with params your treepanel and searchfield on the moment you want to filter the tree.

searchfield is a component where you can extran a raw value from, but you can modify it that it work on a string.

israel.galan
18 Dec 2011, 1:38 AM
Hello,
I have tried this but for some reason the line

var viewNode = Ext.fly(tree.getView().getNode(record));

in the setNodeVisible method is not returning anything for most of the records that are searched, even though I can find them when browsing the DOM.

Any ideas??

tvanzoelen
18 Dec 2011, 2:57 AM
Can you break it apart?



var record = tree.getStore().getNodeById(node.internalId);
var sNode = tree.getView().getNode(record);
var viewNode = Ext.fly(sNode);


Wich var delivers undefined? If internalId is not set properly, the record can not be found.

slemmon
21 Dec 2011, 1:09 PM
Here's what I ended up using so that all matching leaf nodes + parents would be displayed.


searchTree: function (tree, searchfield, property) { // search if a tree component and searchfield (textfield, combo, trigger, etc) are passed as params
if (tree && searchfield) {
// property is optional - will be set to the 'text' propert of the treeStore record by default
property = property || 'text'


var matches = [] // array of nodes matching the search criteria
var rn = tree.getRootNode() // root node of the tree


if (searchfield.getRawValue().length == 0) { // if the search field is empty
tree.collapseAll(); // collapse the tree nodes
return;
}


tree.expandAll(); // expand all nodes for the the following iterative routines


// iterate over all nodes in the tree in order to evalute them against the search criteria
rn.cascadeBy(function (node) {
var re = new RegExp(searchfield.getRawValue(), "ig"); // the regExp could be modified to allow for case-sensitive, starts with, etc.


if (re.test(node.get(property)) == true && node.isLeaf()) { // if the node matches the search criteria and is a leaf (could be modified to searh non-leaf nodes)
matches.push(node) // add the node to the matches array
}
})


var visibleNodes = [] // array of nodes matching the search criteria + each parent non-leaf node up to root
Ext.each(matches, function (item, i, arr) { // loop through all matching leaf nodes
rn.cascadeBy(function (node) { // find each parent node containing the node from the matches array
if (node.contains(item) == true) {
visibleNodes.push(node) // if it's an ancestor of the evaluated node add it to the visibleNodes array
}
})
visibleNodes.push(item) // also add the evaluated node itself to the visibleNodes array
})


rn.cascadeBy(function (node) { // final loop to hide/show each node
var viewNode = Ext.fly(tree.getView().getNode(node)); // get the dom element assocaited with each node


if (viewNode) { // the first one is undefined ? escape it with a conditional
viewNode.setVisibilityMode(Ext.Element.DISPLAY); // set the visibility mode of the dom node to display (vs offsets)
if (Ext.Array.contains(visibleNodes, node)) { // if the the dom node evaluated is contained in the visibleNodes array
viewNode.show() // then hide show it
} else {
viewNode.hide() // else, hide it
}
}
})
}
}

tvanzoelen
22 Dec 2011, 7:04 AM
@slemmon. Nice! Does it work good?

slemmon
22 Dec 2011, 7:23 AM
I have it working in my app now. If I remember correctly I had to write something up for Ext 3, too, 'cuz the tree store filter would show just the first node it came to that matched and I needed all matching nodes to show.

There's probably a more elegant way to write what I did, but it works. :D

tvanzoelen
26 Jan 2012, 4:41 AM
viewNode.setVisibilityMode(Ext.Element.DISPLAY)

this is one broken in 4.1[Beta]. The viewNode is not set on Display mode

tvanzoelen
26 Jan 2012, 5:09 AM
Patch for treefilter 4.1[Beta]. Because setting visibilitymode Display is not working on the viewNode


setNodeVisible: function(tree, node, visible) {

var self = this.screen;

var record = tree.getStore().getNodeById(node.internalId);
var viewNode = Ext.fly(tree.getView().getNode(record));

if (viewNode) {

if (visible == true) {

viewNode.setDisplayed('block');
}
else {
viewNode.setDisplayed('none');
}

}
},

slemmon
26 Jan 2012, 6:43 AM
Hopefully this is fixed in Beta 2.
http://www.sencha.com/forum/showthread.php?170606-4.1-Beta-1-setVisibilityMode(Ext.Element.DISPLAY)-hidden-none&highlight=visibility

tvanzoelen
26 Jan 2012, 6:47 AM
Ah nice you have posted a bugreport on it.

There is another problem with the filter...in 4.1[Beta]


var viewNode = Ext.fly(tree.getView().getNode(record));

is returning null if the node is not expanded.

tvanzoelen
26 Jan 2012, 7:08 AM
This one will work for the Beta 4.1.



treefilter = {

hiddenNodes: new Object(),

searchTree: function(tree, searchfield) {

if (tree && searchfield) {

tree.collapseAll();
//this call probably not needed
this.setNodesVisible(tree, tree.getRootNode());

if (searchfield.getRawValue().length > 1) {
this.searchTreeNode(tree, tree.getRootNode(), searchfield.getRawValue());
}

this.hiddenNodes = new Object();

}

},

searchTreeNode: function(tree, node, query) {

for (var i = 0; i < node.childNodes.length; i++) {
this.searchTreeNode(tree, node.childNodes[i], query);
}

if (this.treeNodeMatch(node, query) == true) {

tree.expandPath(node.getPath());

if (node.parentNode && this.hiddenNodes[node.parentNode.id]) {

while (this.hiddenNodes[node.parentNode.id].length > 0) {
this.setNodeVisible(tree, this.hiddenNodes[node.parentNode.id].pop(), false);
}

delete this.hiddenNodes[node.parentNode.id];
}

this.setNodesVisible(tree, node);

}
else {
if (node.isExpanded() == false) {
this.setNodeVisible(tree, node, false);
}
}
},

treeNodeMatch: function(node, query) {
var re = new RegExp(query, "ig");

if (re.test(node.data.text) == true) {
return true;
}
else {
return false;
}
},

setNodesVisible: function(tree, node) {

for (var i = 0; i < node.childNodes.length; i++) {
this.setNodesVisible(tree, node.childNodes[i]);
}

this.setNodeVisible(tree, node, true);

},

setNodeVisible: function(tree, node, visible) {

var record = tree.getStore().getNodeById(node.internalId);
var viewNode = Ext.fly(tree.getView().getNode(record));

if (viewNode) {

if (visible == true) {

viewNode.setDisplayed('block');
}
else {
viewNode.setDisplayed('none');
}

}
else {

if (node.parentNode) {
if (this.hiddenNodes[node.parentNode.id] == undefined) {
this.hiddenNodes[node.parentNode.id] = new Array();
}

this.hiddenNodes[node.parentNode.id].push(node);
}

}

}
}

seamas
26 Mar 2012, 3:01 AM
The brother is hidden. Great

slemmon
19 Apr 2012, 9:00 AM
Here's what I have for a plugin for tree filter now. Tested with 4.1 RC3. (*example code looks cluttered in the forum window due to lots of commenting. Copy and past into your favorite editor to read it a little easier.)



Ext.define('TreeFilter', {
extend: 'Ext.AbstractPlugin'
, alias: 'plugin.jsltreefilter'

, collapseOnClear: true // collapse all nodes when clearing/resetting the filter
, allowParentFolders: false // allow nodes not designated as 'leaf' (and their child items) to be matched by the filter

, init: function (tree) {
var me = this;
me.tree = tree;

tree.filter = Ext.Function.bind(me.filter, me);
tree.clearFilter = Ext.Function.bind(me.clearFilter, me);
}

, filter: function (value, property, re) {
var me = this
, tree = me.tree
, matches = [] // array of nodes matching the search criteria
, root = tree.getRootNode() // root node of the tree
, property = property || 'text' // property is optional - will be set to the 'text' propert of the treeStore record by default
, re = re || new RegExp(value, "ig") // the regExp could be modified to allow for case-sensitive, starts with, etc.
, visibleNodes = [] // array of nodes matching the search criteria + each parent non-leaf node up to root
, viewNode;

if (Ext.isEmpty(value)) { // if the search field is empty
me.clearFilter();
return;
}

tree.expandAll(); // expand all nodes for the the following iterative routines

// iterate over all nodes in the tree in order to evalute them against the search criteria
root.cascadeBy(function (node) {
if (node.get(property).match(re)) { // if the node matches the search criteria and is a leaf (could be modified to searh non-leaf nodes)
matches.push(node) // add the node to the matches array
}
});

if (me.allowParentFolders === false) { // if me.allowParentFolders is false (default) then remove any non-leaf nodes from the regex match
Ext.each(matches, function (match) {
if (!match.isLeaf()) { Ext.Array.remove(matches, match); }
});
}

Ext.each(matches, function (item, i, arr) { // loop through all matching leaf nodes
root.cascadeBy(function (node) { // find each parent node containing the node from the matches array
if (node.contains(item) == true) {
visibleNodes.push(node) // if it's an ancestor of the evaluated node add it to the visibleNodes array
}
});
if (me.allowParentFolders === true && !item.isLeaf()) { // if me.allowParentFolders is true and the item is a non-leaf item
item.cascadeBy(function (node) { // iterate over its children and set them as visible
visibleNodes.push(node)
});
}
visibleNodes.push(item) // also add the evaluated node itself to the visibleNodes array
});

root.cascadeBy(function (node) { // finally loop to hide/show each node
viewNode = Ext.fly(tree.getView().getNode(node)); // get the dom element assocaited with each node
if (viewNode) { // the first one is undefined ? escape it with a conditional
viewNode.setVisibilityMode(Ext.Element.DISPLAY); // set the visibility mode of the dom node to display (vs offsets)
viewNode.setVisible(Ext.Array.contains(visibleNodes, node));
}
});
}

, clearFilter: function () {
var me = this
, tree = this.tree
, root = tree.getRootNode();

if (me.collapseOnClear) { tree.collapseAll(); } // collapse the tree nodes
root.cascadeBy(function (node) { // final loop to hide/show each node
viewNode = Ext.fly(tree.getView().getNode(node)); // get the dom element assocaited with each node
if (viewNode) { // the first one is undefined ? escape it with a conditional and show all nodes
viewNode.show();
}
});
}
});

hieu79vn
18 Jun 2012, 7:27 AM
Hi
Could you please post a full code for the filter tree please?
I tried to do like your post but don't know how to call the treefilter and functions
Thanks