PDA

View Full Version : Search for a Tree panel



sachintaware
22 Dec 2011, 11:12 PM
Hello
Use Case:
I have a tree panel,which loads records from database.I have to populate a grid based on the click of each record.
Now,as the tree panel has some records the user will have to scroll through them to find a specific one.
So,I want to have a search box which populates the tree items based on the search.On searchin the user can click on the desred link and populate the grid with data.

Something similar to the tree panel here.
http://examples.ext.net/

Any help would be appreciated.
Regards and Happy Holidays
Sachin
www.optionsconsultancy.com

tvanzoelen
22 Dec 2011, 11:57 PM
Look here http://www.sencha.com/forum/showthread.php?154560-treestore-filter-(ext-4.0.7-gpl)

you will find two implementations there.

sachintaware
23 Dec 2011, 12:31 AM
Hello tvanzoelen
Thank you very much for the prompt reply.Hopefully,that should do the trick.
Can you also suggest me some links which have grid populated based on a tree store dynamically.
Like I want "candidate details" to be populated based on the "requirements" in the tree store.
So,each child node in tree store will bring specific set of candidates,and only the content will change nothing else.

It would be of great help.

Regards
Sachin
www.optionsconsultancy.com

tvanzoelen
23 Dec 2011, 12:39 AM
In the case you want to populate the grid with data from the server. You should listen to the select event of the tree. If a select occurs you reload your gridstore and pass the id of the selected node in the load params of the gridstore. Server side you just return the data that matches the passed candidate node id.

sachintaware
23 Dec 2011, 12:47 AM
So,can I do something like getElementByid("node id") in the store load???
I am a newbie,so sorry if it sounds stupid.
Please correct me and if possible point me to any implementation if their.

Regards
Sachin

tvanzoelen
23 Dec 2011, 12:50 AM
Non you listen to the select event of the tree
See http://docs.sencha.com/ext-js/4-0/#!/api/Ext.selection.TreeModel

As incoming argument you have the selected recrod from wich you can get the id. At the point you handle that select event you trigger a store load and pass the coreect arguments wich you have taken from the selected model.

sachintaware
23 Dec 2011, 1:05 AM
So, I will get the selected node using getSelection (http://docs.sencha.com/ext-js/4-0/#%21/api/Ext.selection.Model-method-getSelection)() method.
Now,getSelection().id should give me the id(if I am not wrong).And then trigger a load(Not sure how this is done) on the store and pass it on the id of the selected node.

Am I right???
:-?

Regards
Sachin

tvanzoelen
23 Dec 2011, 1:11 AM
Maybe you should first read some documentation how to listen to event.

Its something like this.



tree.getSelectionModel().on('select', function(selectionModel, record, index){
var params = new Object();
params['id'] = record.get('id');
grid.getStore().load({ params: params});
});

sachintaware
23 Dec 2011, 1:16 AM
Well,I will do that,and thanks for the help.
Will get back if I am not able to fix it. Any sample example would have helped though.I am not able to find any.

Regards
Sachin.

sachintaware
23 Dec 2011, 3:42 AM
Hello tvanzoelen
I tried it but could not get it working.Sharing the code for the same.
ext JS file:


Ext.onReady(function() {

var itemsPerPage = 50;

/***********************Tree panel***************************/
var storetree = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true
},
proxy: {
type: 'ajax',
url: 'RequirementsTree',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'children'

}
}
});


var treePan=Ext.create('Ext.tree.Panel', {
id:'candTree',
renderTo: 'tree',
title: 'Navigation Menu',
width: 300,
height: 450,
useArrows:true,
frame: true,
store:storetree,


});



Ext.define('Company', {
extend: 'Ext.data.Model',
fields: [
{name:'uname',type: 'string'},
{name:'fname',type: 'string'},
{name:'lname',type: 'string'},
{name:'emailid',type: 'string'},
{name:'statename',type: 'string'},
{name:'cityname',type: 'string'},
{name:'countryname',type: 'string'}]
});

var store_company = Ext.create('Ext.data.Store',{
model: 'Company',
remoteSort: true,
pageSize:itemsPerPage,
groupField: 'uname',

proxy: {
type: 'ajax',
url: 'register',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'device',
totalProperty: 'totalCount'
}
}


});

//Group the candidates according to the clients

var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{

groupHeaderTpl: 'Client Name:{name}({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'

});


var grid_company = Ext.create('Ext.grid.Panel', {
store: store_company,
features: [groupingFeature],
id:'x-grid3-row-alt',
remoteSort:false,
columns:[
{
text : 'Client Name',
width : 120,
sortable : true,

dataIndex: 'uname'
},
{
text : 'Requirement',
width : 120,
sortable : true,
dataIndex: 'fname'
},
{
text : 'Name',
width : 110,
sortable : true,
dataIndex: 'lname'
},
{
text : 'Email',
width : 150,
sortable : true,
dataIndex: 'emailid'
},
{
text : 'Phone',
width : 100,
sortable : true,
dataIndex: 'statename'
},
{
text : 'Skills',
width : 170,
sortable : true,
dataIndex: 'cityname'
},
{
text : 'Status',
width : 100,
sortable : true,
dataIndex: 'countryname'
}
],

bbar: Ext.create('Ext.PagingToolbar', {
store: store_company,
pageSize:50,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
}),
id:'candGrid',
height: 450,
width: 922,
title: 'Candidate List',

region:'center',
renderTo: 'grid-company',
viewConfig: {
stripeRows: true
}
});

store_company.load({
params: {
start: 0,
limit: itemsPerPage
}
});






});

});




I get the tree node id by the code you suggested.Now I want the id to be passed to the back-end query as parameter and display result in the grid based on it.

Regards
Sachin

tvanzoelen
23 Dec 2011, 6:19 AM
I do not see the thing I said in your code.

Like something as



treePan.getSelectionModel().on('select', function(selectionModel, record, index, options) {
var params = new Object();
params['nodeid'] = record.get('id');
params['start'] = 0;
params['limit'] = itemsPerPage;

store_company.load({ params: params });

}

sachintaware
23 Dec 2011, 7:08 AM
Sorry for posting the wrong part previously.


store_company.load({
params: {
start: 0,
getid:getid,
limit: itemsPerPage
}

I did something like this instead of an array.
Also,I get a error in firebug saying record is not defined!!
java code


id = request.getParameter("getid");


I acept it like this in the servlet and pass it to the query.
Query:


select * from(select clientname,reqtitle, firstname+lastname as name,emailid,mobile,hc_resume_bank.SkillsText,statustitle as statustitle,ROW_NUMBER() OVER (order by clientname)as row from hc_clients inner join hc_requisitions on hc_clients.rid=hc_requisitions.clientid inner join hc_req_resume on hc_req_resume.reqid=hc_requisitions.rid inner join hc_resume_bank on hc_req_resume.resid=hc_resume_bank.rid)a WHERE row >"+start+" and row <="+finish+" and reqtitle like '%"+id+"%'"


But the response i get it as blank!!
Thanks and Regards
Sachin

tvanzoelen
24 Dec 2011, 2:53 AM
Check in firebug if the id is filled in correctly and posted in the parameters.

sachintaware
24 Dec 2011, 10:55 AM
Hi tvanzoelen.thanks for finding time even during holidays. :)

I got it working,there was a issue in the pagination parameters which did not allow the query to search the entire dataset.

But,now I have another problem.When I click on the node first time,everything works fine.Grid loads perfectly.But when I click on another node after first,it creates a new grid with the data.
I tried using grid.store.removeall() before loading the grid but did not work.
Would like your comments on it.

Regards
Sachin

sachintaware
25 Dec 2011, 10:11 PM
Hello tvanzoelen
Well,thanks to your responses,i have fixed it.

Back to the original "search tree" (Filter) part.I referred your code(function) mentioned in the link,but not sure how can I call it.

Will I have to create a normal textfield or will it need a searchfield ??
I want it to be above the treepanel.Here is my js file.


Ext.onReady(function() {

var itemsPerPage = 50;

/***********************Tree panel***************************/
var storetree = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true
},
proxy: {
type: 'ajax',
url: 'RequirementsTree',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'children'

}
}
});

var searchfield = new Ext.form.TextField({
"id": 'multisite-search-field',
"allowBlank": true,
"width": 200
});
searchfield.renderTo('search');

var treePan=Ext.create('Ext.tree.Panel', {
id:'candTree',
renderTo: 'tree',
title: 'Navigation Menu',
width: 300,
height: 450,
useArrows:true,
frame: true,
store:storetree,


});


/*Handling tree Events*/


//window.alert(getid);

//window.alert('THis is'+record.getId() +'-panel');
Ext.define('Company', {
extend: 'Ext.data.Model',
fields: [
{name:'uname',type: 'string'},
{name:'fname',type: 'string'},
{name:'lname',type: 'string'},
{name:'emailid',type: 'string'},
{name:'statename',type: 'string'},
{name:'cityname',type: 'string'},
{name:'countryname',type: 'string'}]
});

var store_company = Ext.create('Ext.data.Store',{
model: 'Company',
remoteSort: true,
pageSize:itemsPerPage,
groupField: 'uname',

proxy: {
type: 'ajax',
url: 'register',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'device',
totalProperty: 'totalCount'
}
}




});

//Group the candidates according to the clients

var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{

groupHeaderTpl: 'Client Name:{name}({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'

});



var grid_company = Ext.create('Ext.grid.Panel', {

store: store_company,
features: [groupingFeature],
id:'x-grid3-row-alt',
remoteSort:false,
columns:[
{
text : 'Client Name',
width : 110,
sortable : true,

dataIndex: 'uname'
},
{
text : 'Requirement',
width : 145,
sortable : true,
dataIndex: 'fname'
},
{
text : 'Name',
width : 110,
sortable : true,
dataIndex: 'lname'
},
{
text : 'Email',
width : 160,
sortable : true,
dataIndex: 'emailid'
},
{
text : 'Phone',
width : 100,
sortable : true,
dataIndex: 'statename'
},
{
text : 'Skills',
width : 180,
sortable : true,
dataIndex: 'cityname'
},
{
text : 'Status',
width : 90,
sortable : true,
dataIndex: 'countryname'
}
],

bbar: Ext.create('Ext.PagingToolbar', {
store: store_company,
pageSize:50,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
}),
id:'candGrid',
height: 450,
width: 900,
title: 'Candidate List',

region:'center',
renderTo: 'grid-company',
viewConfig: {
stripeRows: true
}
});

treePan.getSelectionModel().on('select', function(selectionModel, record, index,options) {

var getid = record.getId('id');

store_company.load({
params: {
start:0,
getid:getid,
limit:itemsPerPage
}
});

});


/*Search box for tree panel*/

treefilter = {

searchTree: function(treePan, searchfield) {

if (treePan && searchfield) {

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

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

},

searchTreeNode: function(treePan, node, query) {

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

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

this.setNodesVisible(treePan, node);
}
else {
if (node.isExpanded() == false) {
this.setNodeVisible(treePan, 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(treePan, node) {

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

this.setNodeVisible(treePan, node, true);

},

setNodeVisible: function(treePan, node, visible) {

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

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

}

}

});




Expecting a reply from you.

Regards
Sachin

tvanzoelen
27 Dec 2011, 5:51 AM
Just a normal textfield will do. Dock it somwhere in the treeheader

sachintaware
27 Dec 2011, 6:08 AM
I have done something like this,but i get an error in firebug.


var searchfield = new Ext.form.TextField({
id: 'search-field',
allowBlank: true,
width: 200,
renderTo: 'search',
listeners: {
change: {
fn:'searchTree',
scope: this,
buffer: 100
}
}

});

Regards
Sachin

tvanzoelen
27 Dec 2011, 6:15 AM
Then you have to post that error, I can not quess that error.

And .....


fn:'searchTree',

will fail, because searchTree want a treepanel and a textfield as input parameter.

At least you must be able to show a working textfield above a treepanel to get ths working.

sachintaware
27 Dec 2011, 6:28 AM
Sorry
Actually not at my working place...
This is the error I get in firebug when i type any text in the text field.



fn.apply is not a function
http://localhost:9090/Search/lib/ext-all-debug.js
Line 10073




'searchTree(treePan,searchfield)'


same result!

tvanzoelen
27 Dec 2011, 8:23 AM
just create a function around change. I use a key type event for it.

not:

fn: searchTree but wrap a function around it



fn: function(p1, p2){
searchTree(refToTree, refToTextField);
}


It can probably not apply your arguments to the searchTree function.

sachintaware
27 Dec 2011, 9:43 AM
Hello tvanzoelen

Well when I write it as you said I get the error as


searchTree is not defined
http://localhost:9090/Search/lib/candidates.js
Line 31


And when I write it in quotes


fn: function(p1, p2){
'searchTree(treePan, searchfield)';
},


This just does not work,neither gives any error.

Sorry,but knowledge regarding listeners,handlers is not good.
If possible please share the necessary code of yours that worked.

Regards
Sachin

tvanzoelen
27 Dec 2011, 9:51 AM
Then you must bring that function into scope. It can not be found. Is it loaded?

It is impossible to give you my code, because I generate it. I make C# code that generates js code on demand. My apps are to big to post and you probably wont understand the mess that code generator produces. :)

I already gave you the treeFilter.

You must be sure that your js files are properly loaded and you can call its functions.

sachintaware
27 Dec 2011, 7:15 PM
Hello tvanzoelen
I am not sure how this is out of scope??(:|
Please correct,I have highlighted the necessary part for better view.



Ext.onReady(function() {

var itemsPerPage = 50;

/***********************Tree panel***************************/
var storetree = Ext.create('Ext.data.TreeStore', {
root: {
expanded: true
},
proxy: {
type: 'ajax',
url: 'RequirementsTree',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'children'

}
}
});

var searchfield = new Ext.form.TextField({
id: 'search-field',
allowBlank: true,
width: 200,
renderTo: 'search',
listeners: {
change: {
fn: function(p1,p2){
searchTree(treePan,searchfield);

},
scope: this,
buffer: 100
}
}


});

treefilter = {

searchTree:function(treePan, searchfield) {

if (tree && searchfield) {

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

if (searchfield.getRawValue().length > 1)
{
var textval= searchfield.getRawValue();
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) {
treePan.expandPath(node.getPath());

this.setNodesVisible(treePan, node);
}
else {
if (node.isExpanded() == false) {
this.setNodeVisible(treePan, 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(treePan, node) {

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

this.setNodeVisible(treePan, 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.show();
}
else {
viewNode.hide();
}
}

}

}

var treePan=Ext.create('Ext.tree.Panel', {
id:'candTree',
renderTo: 'tree',
title: 'Navigation Menu',
width: 300,
height: 450,
useArrows:true,
frame: true,
store:storetree,


});


/*Handling tree Events*/


//window.alert(getid);

//window.alert('THis is'+record.getId() +'-panel');
Ext.define('Company', {
extend: 'Ext.data.Model',
fields: [
{name:'uname',type: 'string'},
{name:'fname',type: 'string'},
{name:'lname',type: 'string'},
{name:'emailid',type: 'string'},
{name:'statename',type: 'string'},
{name:'cityname',type: 'string'},
{name:'countryname',type: 'string'}]
});

var store_company = Ext.create('Ext.data.Store',{
model: 'Company',
remoteSort: true,
pageSize:itemsPerPage,
groupField: 'uname',

proxy: {
type: 'ajax',
url: 'GridServlet',
actionMethods: {create: "POST", read: "POST", update: "POST", destroy: "POST"},

reader: {
type: 'json',
root: 'device',
totalProperty: 'totalCount'
}
}


});

//Group the candidates according to the clients

var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{

groupHeaderTpl: 'Client Name:{name}({rows.length} Item{[values.rows.length > 1 ? "s" : ""]})'

});


var grid_company = Ext.create('Ext.grid.Panel', {

store: store_company,
features: [groupingFeature],
id:'x-grid3-row-alt',
remoteSort:false,
columns:[
{
text : 'Client Name',
width : 110,
sortable : true,

dataIndex: 'uname'
},
{
text : 'Requirement',
width : 145,
sortable : true,
dataIndex: 'fname'
},
{
text : 'Name',
width : 110,
sortable : true,
dataIndex: 'lname'
},
{
text : 'Email',
width : 160,
sortable : true,
dataIndex: 'emailid'
},
{
text : 'Phone',
width : 100,
sortable : true,
dataIndex: 'statename'
},
{
text : 'Skills',
width : 180,
sortable : true,
dataIndex: 'cityname'
},
{
text : 'Status',
width : 90,
sortable : true,
dataIndex: 'countryname'
}
],

bbar: Ext.create('Ext.PagingToolbar', {
store: store_company,
pageSize:50,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display"
}),
id:'candGrid',
height: 450,
width: 900,
title: 'Candidate List',

region:'center',
renderTo: 'grid-company',
viewConfig: {
stripeRows: true
}
});

treePan.getSelectionModel().on('select', function(selectionModel, record, index,options) {

var getid = record.getId('id');

store_company.load({
params: {
start:0,
getid:getid,
limit:itemsPerPage
}
});

});


});



Regards
Sachin

tvanzoelen
28 Dec 2011, 12:06 AM
change: {
fn: function(p1,p2){
searchTree(treePan,searchfield); <---out of scope

},


searchTree is in the scope of treeFilter, its a method of treefilter. How can you ever call searchTree this way?



change: {
scope: treefilter, //<--don;t know if this works
fn: function(p1,p2){
searchTree(treePan,searchfield);

},


else



change: {

fn: function(p1,p2){
treeFilter.searchTree(treePan,searchfield);
},

sachintaware
28 Dec 2011, 2:30 AM
Hey tvanzoelen
The second one worked!!!!!!!! :)
Thanks a lot,I owe you this one.

But,one question regarding function declarations.In a few examples i found functions written like this


getSearchValue: function() {
var me = this,
value = me.textField.getValue();

if (value === '') {
return null;
}......



Without a header,unlike we have it here



searchfilter={
//here goes the function body.
}


Question:
Can't we write them like the first one?I tried but it did not work.
Reason for this?


Thanks and Regards
Sachin

tvanzoelen
28 Dec 2011, 2:51 AM
In the first one it is a property of a json object. The second one is an assignent to a variable.

sachintaware
28 Dec 2011, 2:54 AM
Thank you again,for bearing with me and sorry for the trouble.
It has really helped me to learn a lot from the forums and guys like you.

Keep up the good work.

Good Luck

Regards
Sachin