Filtering of Hierarchical Data in AdvancedDataGrid is quite straight forward.
Assign the filter function to the ADG’s dataProvider and call refresh() –
// assign filter function to //the AdvancedDataGrid's dataProvider IHierarchicalCollectionView( adg.dataProvider).filterFunction = myFilterFunc; // refresh the ADG's dataProvider IHierarchicalCollectionView( adg.dataProvider).refresh();
Here is a Sample
And the Source
Hey cool ! I didn’t now you finally started a blog .. Cheers !!
Nice post, Thanks
Hello, interesting post but I tried to filter real world data and failed 🙂
Is it is easy because there are only “mx” strings in it ?
How do you filter something more complex, for example :
private var fs2:Object =
{fileName:”something”, children: [
{fileName: “more”, children: [
{fileName: “complex”, size:”5563 bytes”, lastModified:”October 6, 2006″}, …
thank you in advance
The filtering shown in the sample will apply to the whole collection recursively.
In your case, filtering can be applied to a children collection of a node.
You can fetch the children collection using –
var children:ICollection = IHierarchicalCollectionView(
adg.dataProvider).getChildren(node);
And apply filtering on the children collection.
In this way, you can apply different filtering to different children collections.
Sameer, I’m new and I don’t understand your last post. Can you elaborate? Does the children:ICollectionView go in the filterfunction?
Thanks
Let me take an example. Suppose you have –
A
-A1
-A2
B
-B1
-B2
Now, instead of applying the filterFunction to the entire collection you want to fetch the children of B and apply filter.
When you fetch the children using –
var children:ICollection = IHierarchicalCollectionView(
adg.dataProvider).getChildren(node);
A collection will be returned and you can apply sort/filter to that collection.
More information on general sorting/filtering can be viewed here –
http://livedocs.adobe.com/flex/3/html/help.html?content=about_dataproviders_4.html#441147
Looked all over the web for this. Very simple and elegant. Anything similar for the Tree control? Tried iterating filterFunction in a Tree control with limited success. So converted to a single column AdvancedDataGrid and got it all.
Well done.
Sameer, how about if you wanted filter all A, B, A1, A2, B1, and B2 using the same filterfunction?
How do you use custom item renderer with hierarchical data in an AdvancedDataGrid?
I can use custom item renderer with flat data in an AdvancedDataGrid by creating a new class and extending AdvancedDataGridItemRenderer. But when the data is hierarchical it does not work.
Is there some other class I need to extend for hierarchical data?
I just found your post on a 3-state checkbox and figured it out from that code. Thank you!!!
You have to use groupItemRenderer and create a new class and extend AdvancedDataGridGroupItemRenderer.
Awesome!
If you want to change the renderers at the group level, set the groupItemRenderer property in your grid. You can extend from AdvancedDataGridGroupItemRenderer.
And for all the other renderers, there is AdvancedDataGridItemRenderer.
In your example in the May 9th post:
(Let me take an example. Suppose you have –
A
-A1
-A2
B
-B1
-B2)
You have: var children:ICollection = IHierarchicalCollectionView(
adg.dataProvider).getChildren(node);
How do you specifiy that you want the node B. I need to get the count of children in a specific GroupingCollection in my AdvancedDatGrid and then programmatically open the node if it is 1. Your help is very much appreciated! Please email me. Thank you!
Sameer, can you post an example of filtering all nodes in the hierarchy?
The sample that I’ve given in this post filter all the nodes.
Or do you want a sample in which filtering is applied to only a particular node and its children?
Got tricky when applying a text based filter based on datetime field from SQL Server…
item is returning a value of standard SQL Server datetime format…
the user is filtering on date such as ‘7/1/2008’ as text…
data shows different format and is filtering on that value.. not what is shown…
If the value is coming as Strings, the filter should work fine.
Are you applying any formatter to the value?
Sameer, I’m still having issues filtering the advgrid. Can you take a look?
http://s256908546.onlinehome.us/advgrid/index.html
Thanks
If you want to show the leaf nodes also when you type in the Owner, the filter function needs to be changed. Suppose, if you type “work”, it should show all the nodes, right??
Basically, you need to check for each parent if there is a valid child which contains the typed string and then return true/false.
I tried filtering against my advanced data grid and it works great with the only difference that when I finish searching the children under my parent item are not expandable.
Any ideas how I can fix that???
Thanks in advance.
Here is my solution simply my children are IP’s so I just looked for all ips and that did the trickery….
private function searchParams(item:Object):Boolean{
var isMatch:Boolean = false;
var regEx:RegExp = /^([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+\.([1-9][0-9]{0,2})+$/;
if(item.displayValue.toUpperCase().search(txtLookUp.text.toUpperCase()) != -1 || item.displayValue.search(regEx) != -1){
isMatch = true;
}
if(this.reportType == ReportType.ByIP)
{
//DEBUG IP FIELD MAY BE DIFFERENT
if(item.ip.toUpperCase().txtLookUp(txtLookUp.text.toUpperCase()) != -1){
isMatch = true;
}
}
return isMatch;
}
Thanks for the code sample. There’s 1 problem that doesn’t appear in your sample, but does with real world data. That’s when a child node has content that a parent node doesn’t. In that case, if you have a node 2 levels deep that matches, it doesn’t show up because the parent node is hidden. Here’s my solution to that problem:
private function browseFilter(item:Object):Boolean {
var xml:XML = XML(item);
if(xml.children().length() > 0){
var hasValidChildren:Boolean = false;
for each(var node:XML in xml.file){
if(browseFilter(node)){
hasValidChildren = true;
break;
}
}
return hasValidChildren;
}
else {
return String(xml.@path).indexOf(view.browseSearch.text) != -1;
}
}
This will do the actual recursion for each node, and hide it if it doesn’t have any matching children.
Thanks Sean for posting this. Many people must be waiting for this sample to come up.
my datagrid generates a chart.i want to plot another chart based on the child nodes of my datagrid,which should come on clicking a bar.
eg.
chart1:
columnchart dataProvider=”{dg.dataProvider}” itemClick=”DrillDown(event)”
chart2:
columnchart dataProvider=”{AC}”
AC should contain the data of the child nodes of a group(that is represented as a bar in chart1)
hope i stated my problem clearly,please suggest your solution.
Thanks in advance
Hey guys,
I’ver merged Sean’s and Sameer’s code to filter children.
You can get the sample file at this link: http://computerarts.ca/_files/_flex/filtering.zip
When using the Data Management Service with a one-to-many lazy associated data in a HierarchicalData dataProvider, when I apply any filter function other then null, newly opened entities appear twice. This is a serious bug in FDS…
Can you log this issue in the bug base
I was trying to use XML as dataprovider for advancedDataGrid. I tried using Steven’s code. It works like a charm, only that, when I do the search, it only searches child nodes. I want something which can search both parent and child nodes. I have tried
if((ObjectUtil.toString(item)).indexOf(searchText.text)!=-1)
nbsp;nbsp;nbsp;return true;
return false;
this shows up parent, but nothing shows up when I try to expand it. Any updates on this is greatly appreciated
Sounds like I’m running into a similar issue that Ram reported on Feb19. The filtering works great for child nodes, but children of matches get filtered out.
Example:
All Cars
Domestic Cars
Lincoln
Navigator
MTX
Foreign Cars
BMW
X5
M3
Mercedes
GL
SL
So, if I filter on “Mercedes” in this sample, I only get
All Cars
Foreign Cars
Mercedes
where I need to display
All Cars
Foreign Cars
Mercedes
GL
SL
Likewise, if I enter “All” I’d like to get the entire tree instead of just
All Cars
It seems that the filterFunction applies to each node individually, making them get filtered out of the tree if they don’t match the search pattern. Any suggestions on how to include all children of matching nodes?
-tri
Reposting the example tree, hopefully preserving indentation an hierarchy this time.
All Cars
Domestic Cars
Lincoln
Navigator
MTX
Foreign Cars
BMW
X5
M3
Mercedes
GL
SL
i was trying to use apply filter to ADG with HierarchicalData provider but when I try to refresh dataprovider an action script error occurs:
Error #1009: Cannot access a property or method of a null object reference.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.collections::HierarchicalCollectionView/internalRefresh()[C:\Work\flex\dmv_automation\projects\datavisualisation\src\mx\collections\HierarchicalCollectionView.as:700]
at mx.collections::HierarchicalCollectionView/refresh()[C:\Work\flex\dmv_automation\projects\datavisualisation\src\mx\collections\HierarchicalCollectionView.as:681]
at views.questionary::QuestionaryExplorer/filterADGHD()[/usr/local/FilterSample/src/FilterWins/FilterWin1.mxml:438]
at FilterWins::FilterWin1/__searchTextADGHD_change()[/usr/local/FilterSample/src/FilterWins/FilterWin1.mxml:601]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\core\UIComponent.as:9051]
at mx.controls::TextInput/textField_changeHandler()[E:\dev\3.0.x\frameworks\projects\framework\src\mx\controls\TextInput.as:2202]
private function filterADGHD():void{
IHierarchicalCollectionView(adghd.dataProvider).filterFunction = browseFilter;
IHierarchicalCollectionView(adghd.dataProvider).refresh();
}
Can you send a simple sample of what you are trying to do?
I forgot to say that function works fine but when it finishes and return control to IHierarchicalCollectionView(adghd.dataProvider).refresh(); is when error is dispatched.
Any ideas?
Actually, the filter and sort is applied only when refresh() is called.
I have a xml:
var varxml:XML =
;
and then I create a new HierarchicalData object using the previous xml as parameter for constructor:
adgDataProvider = new HierarchicalData(varxml.node);
Then I want to filter by @label when typing in a text input control.
The problem is that when I try
IHierarchicalCollectionView(adghd.dataProvider).refresh();
the action script error occurs.
These are the functions:
private function filterADGHD():void{
// assign filter function to the AdvancedDataGrid’s dataProvider
IHierarchicalCollectionView(adghd.dataProvider).filterFunction = browseFilter;
// refresh the ADG’s dataProvider
IHierarchicalCollectionView(adghd.dataProvider).refresh();
}
private function browseFilter(item:Object):Boolean {
var xml:XML = XML(item);
if(xml.children().length() > 0){
var hasValidChildren:Boolean = false;
for each(var node:XML in xml.node){
if(browseFilter(node)){
hasValidChildren = true;
break;
}
}
return hasValidChildren;
}
else {
var string:String = xml.@label;
return (string.search(searchTextADGHD.text) >= 0);
}
}
The xml do not apprears on the previous post, here it is again less than and greater than simbols in html code:
<node label=”Questionary Categories” type=”root”>
<node label=”cat1″ type=”category” idQuestionaryCategory=”1″>
<node label=”New Questionary6″ type=”questionary” idQuestionary=”86″/>
<node label=”New Questionary5″ type=”questionary” idQuestionary=”77″/>
<node label=”dfgsdfg” type=”questionary” idQuestionary=”4″/>
<node label=”New Questionary” type=”questionary” idQuestionary=”51″/>
<node label=”quest1″ type=”questionary” idQuestionary=”1″/>
</node>
<node label=”mt0lg4t0HZ” type=”category” idQuestionaryCategory=”13″/>
<node label=”jpPq3cSEjK” type=”category” idQuestionaryCategory=”14″>
<node label=”yUcVD6mJGO” type=”questionary” idQuestionary=”18″/>
<node label=”New Questionary” type=”questionary” idQuestionary=”19″/>
</node>
<node label=”CxR8PFrOr2″ type=”category” idQuestionaryCategory=”15″/>
<node label=”XP3CUuh05R” type=”category” idQuestionaryCategory=”16″>
<node label=”New Questionary” type=”questionary” idQuestionary=”21″/>
<node label=”NvI7nzKguL” type=”questionary” idQuestionary=”20″/>
</node>
</node>
Also, i want to say that when i debug the call to the functions, the line
IHierarchicalCollectionView(adghd.dataProvider).refresh();
is called and enters to browseFilter function, i debug it step by step and it loops over all items but when it finishes and return to IHierarchicalCollectionView(adghd.dataProvider).refresh();
is when error occurs. I hope this description helps to understand what i’m trying to do and when the errors occurs,
Thanks!
I created a sample with the data you provided and things seems to work in it.
Can you send me your mail id so that I can send you the sample I created.
My mail id is prosameer@gmail.com
My mail is ddominguez@gcpglobal.com
I have tried the example in
23. Steven – February 11, 2009
Hey guys,
I’ver merged Sean’s and Sameer’s code to filter children.
You can get the sample file at this link: http://computerarts.ca/_files/_flex/filtering.zip
and it works fine so i don’t know why my test do not works
i appreciate you send the example, i will try it and i hope it helps me to solve my problem.
How to do dynamic tree inside advanced datagrid.Please send the code
Please be specific. What exactly do you want to do?
If The Tree is
A
A1
C1
B
B1
C2
I only want to show node starting with C, without parent Node, how can I achive this?
So, filtering will not help much here. How can the children be shown without their parent?
However, you can achieve this in two ways –
1. Create a new XML from the original XML which will contain only the nodes starting with C and use this as the dataProvider for the grid.
2. Create your own implementation of IHierarchicalData and return the filtered children when getChildren() is called for the root node.
sameer, what is going on with the AdvancedDatagrid in the upcoming Flex 4? is there any new enhancements?
There will be some bug fixes and performance improvements.
Do you have any particular enhancement/bug fix in your mind?
Sameer, is it possible to completely change the source dynamically at run-time?
I have an AdvancedDataGrid bound to a flat XML source.
The contents of myXML changes at run-time.
In the method where the contents of myXML changes, I refresh the GroupingCollection:
gcMyGC.refresh();
Doing this gets me the following error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.collections::HierarchicalCollectionView/internalRefresh()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\collections\HierarchicalCollectionView.as:709]
at mx.collections::HierarchicalCollectionView/collectionChangeHandler()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\collections\HierarchicalCollectionView.as:1068]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.collections::GroupingCollection/refresh()[C:\work\flex\dmv_automation\projects\datavisualisation\src\mx\collections\GroupingCollection.as:449]
at…
I forgot to mention that since I’m using a flat data source I’m using a GroupingCollection:
mx:dataProvider
mx:GroupingCollection id=”gcMyGC” source = “{myXML.myElements}”
mx:grouping
mx:Grouping
mx:GroupingField name=”myGroupingField”/
/mx:Grouping
/mx:grouping
/mx:GroupingCollection
/mx:dataProvider
Can you provide a simple sample of what you are doing?
Hi Sameer.
I made a simple sample and sent it to you.
Figured it out.
In case this is useful to someone:
private function bindGrid():void
{
var objGrouping:Grouping = new Grouping();
objGrouping.fields = [new GroupingField(“name”)];
var objGroupingCollection:GroupingCollection = new GroupingCollection();
objGroupingCollection.source = agents.agent;
objGroupingCollection.grouping = objGrouping;
objGroupingCollection.refresh();
adgSales.dataProvider = objGroupingCollection;
}
Hi, its a great example. I was searching for placing elements in the row where a tree node(group) is formed and your example just solved my problem. I tried using the ArrayCollection through AS and everything was working fine. But when I tried the samething using an XML file as a dataprovider, I am not able to get the exact tree structure. Can you please let me know what should be the XML structure in such a case so that it forms the exact same tree structure as when using ArrayCollection.
You can try the sample Steven has posted in Comment #23 above.
Good morning Sameer,
Thanks for your response. The example code behind Comment #23 is where I started. It really gave me a leg up on solving this problem. However, I need all child nodes of a match to be included in my filtered tree.
The only resolution I could muster was a 2-way search. In addition to the ‘hasValidChildren’ approach in Steven’s post, I also have to recursively evaluate parent nodes until node.parent() returns ‘undefined’.
For a quick snippet, I pulled my node-matching code into a separate function that the browserFilter() method can use too. That separate function is matchSearch() The parent search looks like this:
private function hasValidParents(xml:XML, pattern:String):Boolean
{
if ( matchSearch(xml, pattern) ) return(true);
if ( xml.parent() == undefined ) return(false);
return( hasValidParents(xml.parent(), pattern) );
}
and so, if hasValidChildren in browseFilter is false, make the call to hasValidParents().
WARNING: this approach is *much* more expensive than just searching the children. For the dataset size I’m using, I had to stop triggering the filter on the TextInput ‘change’ event. Instead, I filter on ‘enter’.
Check my new post further down.
My xml file is
2009-05-04T10:
27:48+05:30
2009-05-04T10:27:37+05:30
COMPLETED
Operation completed
2009-05-04T10:27:48+05:30
2009-05-04T10:27:36+05:30
I want to show only the children starting with tag….
subOperation tag
sorry not able to paste my xml file dont know hoe to format it
my xml looks like below
-return userID=”senthil-kumarv@hp.com”
–subOperation userID=”11″
—resActions dbid=”7″
—-endTime 2009-05-04T10:27:48+05:30
—subOperation userID=”12″
—subOperation userID=”13″
–resActions dbid=”6″
—endTime 2009-05-04T10:27:48+05:30
And i want to show the children having tag as subOperation
Hello everyone!
I updated my example in order to allow a filter on parent and children.
You can download the latest files here: http://computerarts.ca/_files/_flex/filtering_v2.zip
Thanks to my friend Marc-André for finding a solution!
Cheers
Steven
Thanks Steven and Marc-André. It’s really good to see you guys in action and helping other people.
Hi Sameer… in my filterfunction, only the parent rows are coming through. It seems like the child rows don’t have the filterfunction applied to them. any ideas?
I am using a HierarchicalData tag as the source for my ADG. And I’m applying the filter as such…
IHierarchicalCollectionView(grid.dataProvider).filterFunction = statusFilter;
IHierarchicalCollectionView(grid.dataProvider).refresh();
I’ve figured it out.. thanks anyways..
Hi Omar,
I am facing the same issue. Could you please share the code that you are using. I have created hierarchical data from nested arraycollection.
Sameer Ali Khan
I am building a basic ADG with a renderer showing the children.
A good example (not mine) is http://www.objectsatellite.com/html/FlexSolutions/ADGWithContainedADG/DataGridWithChildDataGrid.html
However when I apply a filter to the parent data (e.g name) then the children under the filtered rows do not show.
Any Ideas?
Please have a look at comments #23 and #50.
Steven has posted a sample for this.
In case you are looking for a component that does advanced datagrid filtering, there is one available at flexicious
Hello Sameer,
I need a clarification , Actually I need to show the node along with the filtered child which is case insensitive and it should ignore the whitespaces .
So right now , I am able to show only the filtered node
like this
private function myFilterFunc(item:Object):Boolean
{
return item.task.match(new RegExp(textSearch.text,”si”));
}
where “task” is the datafield for filtering.
When I tried , filteringv2 by Steven , I am not getting any row.
(I have just tried , what it was and replaced the datafield alone ,no reg exp) ..Can you help in this regard.
The best way to filter a AdvancedDataGrid is to apply the filter function to the AdvancedDataGrid’s Grouping Collection instance and then do a refresh to that instance thats it.
a sample snippet how i implemented to a complex hierarchical Data.
public function filterChanged(filter:String):void
{
ADGfilterString=filter;
// myGColl is my GroupingCollection instance name myGColl.source.filterFunction=myFilterFunc;
myGColl.refresh();
ADG.dataProvider=myGColl;
//(ADG is my AdvancedDataGrid instance name)
}
And my Filter function is
public function myFilterFunc(item:Object):Boolean
{
if(ADGfilterString!=”ALL”)
if(item.name!=ADGfilterString)
return false;
return true;
}
I am passing an ArrayCollection as data provider to the datagrid. When using IHierarchicalCollectionView(datagrid.dataProvider).filterFunction = filterADG; I am getting the item as normal object instead of XML object in my function filterADG. Please help me to resolve this.
Can you provide some more information –
Does your ArrayCollection consists of XML data?
Are you grouping the data using GroupingCollection?
Man, you save my life, really.
thank you very much.
Hi Sameer,
Your example is very helpful.But I too have faced the same problem as you filtering only the parent node and child nodes not showing up after filtering.Though the problem is solved by having the dataprovider as XML in my scenario I will be using only ArrayCollection as a dataprovider is there any solution for displaying the child nodes also after filtering the particular parent node.