Tuesday, November 07, 2006

ListCollectionView: Different perspectives on data

In a recent project one of the challenges was to display data to the user in a variety of different ways with little overhead. In the .net world we used DataViews to create multiple perspectives on the same DataSet. This included sorting and filtering the data without needing multiple copies of the data in memory. When I first started snooping around in Flex I figured there had to be a way to get the same functionality, and soon I found the ListCollectionView.

As a side note, I'll soon start putting running samples up here with source code, just been too lazy to ftp them up to my server. Anyway let's dig in to the code. First we have a handy dandy xml data file:

<?xml version="1.0" encoding="UTF-8"?>
<items>
<item name="Item 1" quantity="2" price="20.00" size="small"
rebate="yes" discontinued="yes" />
<item name="Item 2" quantity="4" price="10.00" size="medium"
rebate="no" discontinued="yes" />
<item name="Item 3" quantity="4" price="25.00" size="small"
rebate="no" discontinued="no"/>
<item name="Item 4" quantity="1" price="5.00" size="extra-large"
rebate="no" discontinued="yes" />
<item name="Item 5" quantity="3" price="30.00" size="small"
rebate="yes" discontinued="yes" />
<item name="Item 6" quantity="4" price="17.00" size="medium"
rebate="no" discontinued="yes" />
<item name="Item 7" quantity="1" price="12.00" size="extra-large"
rebate="yes" discontinued="no"/>
<item name="Item 8" quantity="4" price="22.00" size="extra-large"
rebate="yes" discontinued="yes" />
</items>
Then we have to load the xml into an arraycollection, however several of the boolean properties will need to be reworked during the data load. Here's what that looks like:
<mx:HTTPService id="itemConn" url="items.xml"
useProxy="false" result="resultItemHandler(event)"/>
...

private function resultItemHandler(event:ResultEvent):void {
var source:ArrayCollection =
itemConn.lastResult.items.item as ArrayCollection;
var cursor:IViewCursor = source.createCursor();
var result:ArrayCollection = new ArrayCollection();
while (!cursor.afterLast){
var currentObj:Object = cursor.current;
var cv:String = currentObj["rebate"];
cv = cv.toUpperCase();
var newValue:Boolean = false;
if (cv == "YES" ){
newValue = true;}
currentObj["rebate"] = newValue;
cv = currentObj["discontinued"];
cv = cv.toUpperCase();
newValue = false;
if (cv == "YES" ){
newValue = true;}
currentObj["discontinued"] = newValue;
result.addItem(currentObj);
cursor.moveNext();
}
itemsIS = result;
}
So now we have an ArrayCollection of itemsIS, let's add a DataGrid and set the dataprovider to this collection:
<mx:DataGrid id="itemDG" dataProvider="{itemsIS}"
editable="false" width="100%" height="100%"/>
The next step requires a filtered view that will only show discontinued items, so we're going to add a LinkButton
<mx:LinkButton label="Discontinued" click="handleDisc()"/>
and then add the following code to our script section:
[Bindable]
private var itemsDiscontinued:ListCollectionView;
public function handleDisc():void{
itemsDiscontinued = new ListCollectionView(itemsIS);
itemsDiscontinued.filterFunction =
function ( item:Object):Boolean {return item.discontinued};
itemsDiscontinued.refresh();
itemDG.dataProvider = itemsDiscontinued;}
In this function we are creating a ListCollectionView that wraps our itemsIS collection. Then we create and set the filter function inline, and call a refresh(). Then we set the dataProvider of the datagrid to our ListCollectionView. You could add any number of "views" on the data in this way, and then let the user switch quickly between them.
Here's the code in action

1 comment:

Anonymous said...

It may be a long time on since the original post, but thanks for such a great example.

Paul