Rich Internet applications developed with Flex benefit of many of the built-in functionality already provided by this framework. One of such enhancement is the filterFunction, that can be applied to instances of class ListCollectionView (and extending ones, such as the more commonly used ArrayCollection) and allows for fast and easy to implement filtering of data. This feature, used with advanced visualization controls as DataGrid or List, provides a rich environment for the end user, that can fully control the data he/she is working with.
The filter function is best suited with visualization controls that do not consider hierarchical data, but there may be cases in which the filter should be applied to hierarchical objects, displayed, for example, into a Tree component. If we apply the filterFunction to the data provider of a Tree component, the filter will only be applied to the first elements in the hierarchy and will not be applied to nested children. This may appear as an unwanted feature of the Tree, but it was actually meant to be that way, as the Tree control strives to be as independent as possible from the underlying displayed data and allows for personalization through it's descriptor.
In order to filter all nodes of a Flex Tree component, the solution is to apply the filter function to each nested element of the data provider. This can be accomplished by creating a new hierarchical structure, already filtered (can be rather expensive), or using dynamic filtering over the Tree's default descriptor, as shown below.
I extended the DefaultDataDescriptor used by the Tree, into a FilteredDataDescriptor, that has an additional field, namely filterFunction, which is applied as filter to each element of the nested structure:
private var _filterFunction:Function;
public function get filterFunction():Function {
return _filterFunction;
}
/**
* Applies this filter function to the children of every node.
* @param value
*/
public function set filterFunction(value:Function):void {
_filterFunction = value;
}
In order to apply the filter to the children of the data provider we can override getChildren() and, before returning the collection of children, apply the filter function:
override public function getChildren(node:Object, model:Object=null):ICollectionView {
var collection:ICollectionView = super.getChildren(node, model);
if (collection && (collection is ListCollectionView)) {
(collection as ListCollectionView).filterFunction = _filterFunction;
}
return collection;
}
Note that this will work only for classes extending ListCollectionView (obviously Array is out of the picture) and that we also do not need to specifically call refresh() on the children collection, as it will be called later by the framework itself. All that's left now is to assign the newly created tree descriptor to a Tree and pass it the proper filter function(s).