The Flex DataGrid is a very powerful and useful component but there are some things that it just won't do out of the box. One of the features that is built in but not used by default is custom sorting functions. The DataGrid will sort most basic object types by default, but if you have a complex object that you need to sort it has to be done using a custom function. This tutorial is going to show how to build and use a custom sorting function in a DataGrid.
One of the most useful examples is going to be when a date is used as string but you still want to be able to sort the column. This is going to require just a couple simple steps. Before we jump into the code you can see an example of what we are going to do below. You can view the source code by right-clicking the application.
To get started we are first going to create the basic application with the DataGrid. This is pretty much as simple as it gets.
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="400" height="200">
<mx:DataGrid width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name" width="125" />
<mx:DataGridColumn dataField="artist" headerText="Artist" width="125" />
<mx:DataGridColumn dataField="date" headerText="Date" width="100"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
As you can see from above we have 3 columns, the fields these are going to look at are name, artist, and date. To make life easier I created a simple object to hold these properties. The class created is named Album. The massive amount of code for this follows.
{
public class Album
{
public var name:String;
public var artist:String;
public var date:String;
}
}
We need to do a little more book keeping to actually get some information on the screen. To get some values in our grid we add a script block and an initialization function. The init function will fill a variable that our grid will bind to.
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var albums:ArrayCollection;
private function init():void
{
var album:Album;
albums = new ArrayCollection();
album = new Album();
album.name = "Who's Next";
album.artist = "The Who";
album.date = "Jul 31 1971";
albums.addItem(album);
album = new Album();
album.name = "Exile on Main St.";
album.artist = "The Rolling Stones";
album.date = "May 12 1972";
albums.addItem(album);
album = new Album();
album.name = "Sgt. Pepper's Lonely Hearts Club Band";
album.artist = "The Beatles";
album.date = "Jun 1 1967";
albums.addItem(album);
album = new Album();
album.name = "The Doors";
album.artist = "The Doors";
album.date = "Jan 4 1967"
albums.addItem(album);
album = new Album();
album.name = "The Wall";
album.artist = "Pink Floyd";
album.date = "Dec 8 1979";
albums.addItem(album);
}
]]>
</mx:Script>
Calling this function is simply done by hooking into the creationComplete event on the main application.
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="400" height="200"
creationComplete="init()">
Binding to the DataGrid is also very easy. We just bind the dataProvider on our grid to the albums variable.
You should have a working demo now. The problem is that if you start to play around with the sorting it seems to work for the name and artist but date is a little confused. The first step is to tell the column we are going to use a custom sorting function. This is done by setting the sortCompareFunction property. The value set is a function name which in our case is going to be sortDate.
sortCompareFunction="sortDate"/>
The sortDate function takes two objects in (the ones being compared) and returns an int. The returned value should be -1 if the first object should come first, 0 if they are equal, and 1 if the second object should come first. The sorting function is below, I will go over the details right after.
{
var d1:Number = (new Date(Date.parse(obj1.date))).getTime();
var d2:Number = (new Date(Date.parse(obj2.date))).getTime();
if(d1 < d2) {
return -1;
} else if(d1 == d2) {
return 0;
}
return 1;
}
Above we start by parsing the dates for the two albums. This is done using the Date.parse function, which is passed into a new Date object and finally I call getTime on the object to get a number in milliseconds to compare. All that is left in the function is to actually compare the values. With that our code is done, now if you run the demo you should notice that the dates now sort correctly.
To finish up here is the complete code for our main file.
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
width="400" height="200"
creationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridColumn;
import mx.collections.ArrayCollection;
[Bindable]
private var albums:ArrayCollection;
private function init():void
{
var album:Album;
albums = new ArrayCollection();
album = new Album();
album.name = "Who's Next";
album.artist = "The Who";
album.date = "Jul 31 1971";
albums.addItem(album);
album = new Album();
album.name = "Exile on Main St.";
album.artist = "The Rolling Stones";
album.date = "May 12 1972";
albums.addItem(album);
album = new Album();
album.name = "Sgt. Pepper's Lonely Hearts Club Band";
album.artist = "The Beatles";
album.date = "Jun 1 1967";
albums.addItem(album);
album = new Album();
album.name = "The Doors";
album.artist = "The Doors";
album.date = "Jan 4 1967"
albums.addItem(album);
album = new Album();
album.name = "The Wall";
album.artist = "Pink Floyd";
album.date = "Dec 8 1979";
albums.addItem(album);
}
private function sortDate(obj1:Object, obj2:Object):int
{
var d1:Number = (new Date(Date.parse(obj1.date))).getTime();
var d2:Number = (new Date(Date.parse(obj2.date))).getTime();
if(d1 < d2) {
return -1;
} else if(d1 == d2) {
return 0;
}
return 1;
}
]]>
</mx:Script>
<mx:DataGrid width="100%" height="100%" dataProvider="{albums}">
<mx:columns>
<mx:DataGridColumn dataField="name" headerText="Name" width="125" />
<mx:DataGridColumn dataField="artist" headerText="Artist" width="125" />
<mx:DataGridColumn dataField="date" headerText="Date" width="100"
sortCompareFunction="sortDate"/>
</mx:columns>
</mx:DataGrid>
</mx:Application>
I should also mention that the Date.parse function is pretty particular on what string format it will take in. There is, however, another library called Actionscript Corelib that has a date parsing utility that may help in certain situations.
With that my work is done for this tutorial. I hope that it was informative. If you have any questions feel free to leave a comment or head on over to our forums.
03/03/2010 - 21:18
We actually have a grid that solves the issue of the inital sort icon, both on classic and advanced datagrid with multicolumn sort, also sorting/filtering by dates/numbers/booleans where the actual data is string and a intermediate conversion is required before the sort/filter operation. Please take a look at http://www.flexicious.com.
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.