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.
<?xml version="1.0" encoding="utf-8"?>
<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.
package
{
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.
<mx:Script>
<![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.
<mx: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.
<mx:DataGrid width="100%" height="100%" dataProvider="{albums}">
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.
<mx:DataGridColumn dataField="date" headerText="Date" width="100"
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.
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;
}
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.
<?xml version="1.0" encoding="utf-8"?>
<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.
Source Files:
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.
Nice article. I have used this snippet in my project and its working fine.
You can optimize your sortDate function to avoid unnecessary checking and code branching:
This makes it both simpler and a bit faster to execute.
Si deseas usar la funcion que ya trae el datagrid, utiliza:
Hello there, I had just found this topic with a question: Is a DataGrid able to be sorted by scripts? I don't know whether I should modify the dataProvider or just call a function.
Can anybody tell me how to do it?