If you’ve ever used an AdvancedDataGrid, chances are you’ve encountered HierarchicalCollectionView. If you’ve ever used an AdvancedDataGrid for anything remotely complex, chances are you’ve cursed and shaken your metaphorical fists at HierarchicalCollectionView.
There are likely myriad reasons to despise this class but the one that burned me was this gem: any filterFunction applied to your HierarchicalCollectionView is also applied directly to your underlying child collections. In case the ramifications of that are not immediately clear, what it means is that you cannot simultaneously have two distinct views of a single data set that you have wrapped into a HierarchicalCollectionView. In fact, once applied you will have to manually clear the filter from underlying collections in order to get them back to normal. Because of this, the class is of extremely limited utility, and I would submit that its name is highly misleading. The ‘View’ at the end of the name implies that it will be creating a “virtual” view of the underlying data, leaving the source intact. This is how the immensely useful ListCollectionView class works. Apparently, other languages/frameworks also have “collection view” classes that do not modify the underlying data, so this is quite a departure from convention, not to mention common sense.
If you happen to look at the docs for HierarchicalCollectionView you will notice that filterFunction isn’t even listed as a supported property. Maybe the thinking was if they don’t tell anyone about it, we’ll overlook how poorly implemented it is?
Adobe has made the decision to prefix all skinnable components in Flex 4 with the letters Fx, resulting in class names like FxButton, FxCheckBox, etc. They have also stated that if community disagreement were strong enough they would consider reversing this decision. Please use this form to submit your opinion.
http://bit.ly/AxeFx
Spread the word and make others aware of the form as well. The more responses the better.
Update: Manish Jethani, former Flex Team engineer, has written a post detailing why this is such a bad solution. Its really great to see this, not only because I obviously have a lot of respect for Manish, but also because his post is what I would have written if I had the time. He lays out an argument virtually identical to the one in my head, but I think it carries more weight coming from him. So thanks for the backup Manish, and to everyone else, go read it!
Update 2: I’ve made the results sheet public so anyone can view it. Check it here. Note this does not mean the survey is over, just letting everyone see results as they come in. Sorry its just a spreadsheet, blame Google.
I recently needed to show a set of hierarchical data in a Flex List component. By default, the List component displays a one dimensional, or flat, set of data. In my case the hierarchy was to be shown by displaying the top level objects as dividers with a different visual appearance than their child items. The wrong way to do that would be to create a whole new list that is flat, with some artificial property to differentiate top level objects from children.
I remembered hearing Deepa talk about some sort of virtual lists at MAX 2007, so I started Google-ing. Turns out she was talking about IList implementations. Unfortunately, her examples and every other example I found demonstrated using IList to virtually merge two separate, but related lists of objects. This wasn't what I needed, but it put me on the right track.
As it turns out, the only parts of IList you have to implement are the length getter and the getItemAt() method. I realized that by having control over getItemAt(), you could essentially hide what your list actually contains and return whatever you want. The result is FlattenedList (source). For the lazy and impatient (that includes me) I have included the two most important pieces here:
public function FlattenedList
( items:
Array, subCollectionFieldName:
String )
{
// store master list
this.
items = items;
this.
subCollectionFieldName = subCollectionFieldName;
// the first grouping will obviously start at zero
topLevelObjectIndexes.push( 0 );
for each( var obj:Object in items )
{
// create internal length var to hold total number of items, regardless of level
_length += obj[ subCollectionFieldName ].length + 1;
// the next grouping will begin at the index equal to the total number of items already counted
topLevelObjectIndexes.push( _length );
}
// remove last entry since its for next grouping, which doesn't exist
topLevelObjectIndexes.pop();
}
public function getItemAt
( index:
int, prefetch:
int =
0 ):
Object
{
// iterate over our list of index dividing points
for( var i:
int =
0; i <topLevelObjectIndexes.
length; i++
)
{
// if the requested index is between the current and next stored index
// or we've reached the last stored index, use this top level object
if( index>= topLevelObjectIndexes
[ i
] &&
( index <topLevelObjectIndexes
[ i +
1 ] || i == topLevelObjectIndexes.
length -
1 ) )
{
// get a ref to the top level object
var topLevelObject:
Object = items
[ i
];
// get the "local index" that will be applied to selected top level object
var indexDelta:
int =
index - topLevelObjectIndexes
[ i
];
// if requested index is equal to stored start index we return the top level object itself
if( indexDelta == 0 )
{
return topLevelObject;
}
else // otherwise we return one of its child objects
{
return topLevelObject[ subCollectionFieldName ][ indexDelta - 1 ];
}
}
}
return {};
}
The code is heavily commented and fairly straightforward so I won't try to explain it here, but take a look and see what you think. I will provide some disclaimers that I only implemented as much as I needed, so there are several unimplemented IList methods in the class. I did implement toArray() because its required to support sorting and filtering. I suppose a better approach might be to subclass an existing IList implementation and just override what you need. As it turns out, ListCollectionView is the only IList implementation in the Flex framework and its a great class that will probably be the subject of a future blog post here.
Lastly, it probably wouldn't take much tweaking to allow FlattenedList to support an infinite/variable level of nesting versus the single level it supports right now. Anyone out there up for a challenge?
Recent Comments