January 06 2009
Flex Trees can be difficult to filter because of their hierarchical nature. One possible way to do it is to use an ArraryCollection as your dataProvider, with each node having a "children" property that is also an ArrayCollection.
The tricky part in filtering the Tree is making sure the children are filtered in addition to the root nodes. So, in the example below, I have created a function that will loop through each node and its children recursively.
It is important to note that the filtering takes place from the bottom up, meaning that a node's children are always filtered before the node itself. This is important, because normally a filter removes everything that does not match a certain criteria. In our case, to remain in the collection, a node must match a certain criteria OR have children that do.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="
http://www.adobe.com/2006/mxml"
layout="absolute">
<mx:Script>
<![CDATA[
import vo.Person;
import mx.collections.ArrayCollection;
[
Bindable]
private var people:ArrayCollection =
new ArrayCollection([
new Person("
Grandma Susan",
new ArrayCollection([
new Person("
John",
new ArrayCollection([
new Person("Timmy"),
new Person("Sammy"),
new Person("Alan")
])),
new Person("
Tiffany",
new ArrayCollection([
new Person("Billy"),
new Person("Adam"),
new Person("Graham"),
new Person("Vennesa")
])),
new Person("
Michael",
new ArrayCollection([
new Person("
Jannette"),
new Person("
Alan",
new ArrayCollection([
new Person("Alice"),
new Person("Jane")
]))
])),
new Person("
Peter"),
new Person("
Cindy",
new ArrayCollection([
new Person("Paul"),
new Person("David"),
new Person("Joseph"),
new Person("Cameron"),
new Person("Debra"),
new Person("Polly")
]))
]))
]);
private function refreshData():
void{
people[0].children = new ArrayCollection(people[0].children.source);
refreshRecursiveChildren(people.source[0]);
personsTree.invalidateList();
}
private function refreshRecursiveChildren(person:Person):
void{
if(person.children){
for each(
var _person:Person
in person.children.source){
refreshRecursiveChildren(_person);
}
person.children =
new ArrayCollection(person.children.source);
person.children.filterFunction = filterData;
person.children.refresh();
}
}
public function filterData(item:Object):Boolean{
var searchString:String = iNameFilter.text;
if(searchString.length == 0
|| item.name.toLowerCase().indexOf(searchString.toLowerCase()) >= 0)
return true;
else if(item.children !=
null && item.children.length > 0)
return true;
return false;
}
]]>
</mx:Script>
<mx:VBox width="
100%" height="
100%"
paddingTop="10"
paddingBottom="10"
paddingLeft="5"
paddingRight="5">
<mx:Tree id="
personsTree"
dataProvider="{people}"
labelField="name"
width="100%"
height="100%" />
<mx:HBox>
<mx:Label text="Filter the Tree:" />
<mx:TextInput id="iNameFilter" change="refreshData()" />
</mx:HBox>
</mx:VBox>
</mx:Application>
You may right-click and select "View Source"
to view the full source code for the following example.
Posted in Flex | ActionScript | How-To
December 30 2008
If you haven't checked out Tour de Flex I suggest you do. It is an Air app that contains over 200 working applications, all with source code. Everything from simple Flex components to advanced filters and working with Air is covered, so there's something for everyone, beginners to advanced developers alike.
Posted in Flex | AIR | Miscellaneous
December 23 2008
Just in time for Christmas, Kap Lab has released version
1.1.0 of its data visualization components.
In addition, two new developer tools have been released: the Cairngorm
Console and the PureMVC Console. All Kap
Lab’s components are free and are extremely useful. I suggest you give them a look.
Posted in Flex
December 13 2008
One of the bad things about using itemRenderers in a DataGridColumn is that you lose the dataTip functionality that it normally provides. Well, here is a way to fake that functionality.
First, add the dataTipField or dataTipFunction to the DataGridColumn like you normally would.
<mx:DataGridColumn headerText="
DataTip"
dataField="name1"
showDataTips="true"
dataTipField="description1" />
Then, in your itemRenderer add the following code to be able to tap into that information and display a tooltip instead.
private function getToolTip():String{
var dg:DataGrid = listData.owner
as DataGrid;
var func:Function = dg.columns[listData.columnIndex].dataTipFunction;
if(func !=
null){
return func.call(this, this.data);
}
else if(dg.columns[listData.columnIndex].dataTipField.length){
return data[dg.columns[listData.columnIndex].dataTipField];
}
else{
return "";
}
}
override protected function updateDisplayList(unscaledWidth:Number,
unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
this.toolTip = getToolTip();
}
This works with both dataTipFields and dataTipFunctions and lets you treat the dataTips in your columns the same way, regardless of whether you're using an itemRenderer or not. The only minor difference is the positioning of the label, but that can be easily modified with styles. You can download the full source code here, for a functional example of how this works.
Posted in Flex | ActionScript | How-To
December 08 2008
In a previous post I explained how a rendering bug in Flex was causing items to disappear in an itemRenderer. In the example below, you can see that when you scroll, the items in the list disappear. This is caused by the varying heights of the elements. If you explicitly set the height for each element or set variableRowHeights to false, then the problem goes away.
What was causing the problem was apparent but the solution was not. Thankfully, Olivier Lalonde was nice enough to shed some light on an easy fix. The itemRenderer needs to be validated as the user scrolls. So, as Olivier suggests, you simply need to listen for the dataChange event and execute the validateNow() function.
You can see in the example below that the list now has varying row heights... and the data no longer disappears. NICE! The key point to focus on here is the following line: <mx:VBox dataChange="validateNow()" verticalGap="0">
<mx:List
dataProvider="
{myData.item
}"
variableRowHeight="
true"
alternatingItemColors="
['#FFFFFF','#E6EEF3']"
width="
100%"
height="
100%"
>
<mx:itemRenderer>
<mx:Component>
<mx:VBox verticalGap="
0" dataChange="validateNow()"
>
<mx:HBox>
<mx:Label text="{data.Label}" fontWeight="bold" />
<mx:Label text="{data.date}" color="#999999" />
</mx:HBox>
<mx:Text text="
{data.description
}" width="
100%"
/>
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:List>
Posted in Flex | ActionScript | Bugs | How-To