Mike Chambers

code = joy

Sorting Date fields in a DataGrid in the Flex Framework

with 16 comments

I was working on some new mini chart apps over the weekend for the MXNA reports section, and had a DataGrid that contained dates. I wanted to allow the user to sort the datagrid by the DateField, but by default the DataGrid sorts dates with a string compare (calling toString on the Date instance).

I tried to set up a custom sort function for the DataGridColumn instance that contained the dates, but because I was using a custom label format function for the column, Flex passed the labels to me, and not the data items (which would allow me to get access to the Date instance). Because of this, I couldn’t sort on the date.

There is an example on Macromedia.com that shows how to sort by dates, but it requires that you override and implement all sorting for the DataGrid (something which seemed unecessary and overkill to me). Peter Ent also posted an example, but it required massaging the data on the server first, something which was not an option for me since I was using a public web service API.

So, after much trial and error, and help from Matt Chotin, I finally got it working, and figured I would post it here.

Basically, I listen for the headerRelease event for the DataGrid. If it is in response to the date column being clicked, then I sort the dataprovider that the DataGrid is hooked up to (otherwise, I do nothing, and let the DataGrid do the sorting).

Here is an example:

Here is the Code:

———-DateSortExample.mxml———-

<?xml version="1.0"?>

<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" initialize="initTag()"
	backgroundColor="0xFFFFFF" marginTop="0" marginLeft="0" marginRight="0" marginBottom="0">		

	<mx:Script source="DateSortExample.as" />   

	<mx:Panel title="DataGrid Date sorting example" width="475" height="350">

	    <mx:DataGrid id="dg" height="100%" width="100%">
	        	<mx:columns>
		        <mx:Array>
            	        <mx:DataGridColumn headerText="Letters" width="50" columnName="letter" />
            	        <mx:DataGridColumn headerText="Numbers" width="50" columnName="number" />
            	        <mx:DataGridColumn headerText="Dates" columnName="date" />
            	   </mx:Array>
            	</mx:columns>
	    </mx:DataGrid>

	</mx:Panel>
</mx:Application>

—————————————-

———-DateSortExample.as———-


private var dp:Array;
private var sortOrder:Number = 1;

private  function initTag():Void
{
	//listend for the headerRelease event on the datagrid, which is broadcast
	//when any of the column headers are clicked.
	dg.addEventListener("headerRelease",
		mx.utils.Delegate.create(this, onDateHeaderRelease));

	dp = new Array();

	//pupulate the date grid with some data.
	var item:Object;
	var randomDay:Number;
	var randomMonth:Number;
	for(var i:Number = 0; i < 15; i++)
	{
		randomDay = Math.floor(Math.random() * 30);
		randomMonth = Math.floor(Math.random() * 12);

		item = new Object();
		item.date = new Date(2005, randomMonth, randomDay);
		item.letter = String.fromCharCode(i + 65);
		item.number = i;

		dp.push(item);
	}

	//set the dataProvider for the datagrid
	dg.dataProvider = dp;
}

//Note, this should be in a DateUtils class
/*
	returns
	-1 : first date is larger than the second
	 1 : first date is smaller than the second
	 0 : Both dates are the same
*/
private static function compareDates(d1:Date, d2:Date):Number
{
	var d1ms:Number = d1.getTime();
	var d2ms:Number = d2.getTime();

	if(d1ms > d2ms)
	{
		return -1;
	}
	else if(d1ms < d2ms)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//compares the dates
private function dateFieldCompare(item1:Object, item2:Object, bit:Number):Number
{
	//determine which way the column should be sorted (ASC or DESC
	var toggle:Number = (bit == Array.DESCENDING)? 1 : -1;

	//call compare date function, and then toggle the sort direction
	return toggle * compareDates(item1.date,item2.date);
}

//called when any of the datagrids column headings are clicked
private function onDateHeaderRelease(eventObj:Object):Void
{
	//Only sort if the Date column head was clicked
	if(eventObj.columnIndex == 2)
	{
		//sort the dataProvider directly, passing the function to do the sort
		//and a bit indicating whether to sort ascending or descending
		dp.sortItems(dateFieldCompare, ((sortOrder == 1)? 0: Array.DESCENDING));

		//reverse the sort order so the next time the column is clicked, it is
		//sorted in the reverse order
		sortOrder *= -1;
	}
}

—————————————-

You can download the source from here (or right click on the example).


Creative Commons License

This work is licensed under a Creative Commons License.

16 Responses to 'Sorting Date fields in a DataGrid in the Flex Framework'

Subscribe to comments with RSS

  1. excellent !

    is there a way do do the same in flash ???

    2e question, the flex datagrid component looks better that the flash one? can we use it in the flash ide ?

    Regards

    CR

    CR

    28 Apr 05 at 7:50 am

  2. Hey Mike,

    Very useful! I had an almost indentical situation a few weeks ago. A project I had using a datagrid recquired that every time the datagrid was displayed it showed the most recent dated recordsets starting at the top, descending on down to the oldest. The problem was the # of records the client wanted to display without paging data, I couldnt sort them ahead of time, and the format the date was coming in didnt lend itself to converting quickly enough in flash for a good compare routine. My sort routine ended up bogging everything way down and exceeding the built in scriptLimits. I overrode that temporarily until I could get a fix in place. Since this was a kiosk project, I already had a Visual Basic wrapper surrounding the Flash content, so I took advantage of that, and used VB to reformat the data and put it into a Dictionary object, sorted it on an extra re-formatted date field, then popped it back into flash as a serialized dataset. I let flash deserialize it – basically a series of splits, which go pretty fast in Flash, then I repointed the dataprovider to the newly deserialized data and everything was cool. Went from 45 seconds down to less than 6 with 1000′s of records. Not the most elegant solution if your trying to stay all in Flash – but it worked pretty well. I’ll give this sort routine a try next time around.

    Good post!
    Rob

    Robert M. Hall

    28 Apr 05 at 5:44 pm

  3. If you want to do the same thing in flash you can have an additional field in the dataprovider array. This field contains the date value represented as number.
    eg: jan 04 2005 is represented as “20050104″ . You can then do a numeric sort on this field.

    regards
    Kiran

  4. ok thx =)

    the code works inside flash =)

    CR

    CR

    30 Apr 05 at 5:51 pm

  5. Thank you :)

    Vee

    5 Aug 05 at 3:50 am

  6. Gentlemen,

    I’m not a flash programmer nor flex and I am wondering if you know of an ‘out-of-the-box’ solution for a datagrid that we could use on a website build in DM with Php?

    Basically, I’m looking for a dynamic datagrid that populates from a table and allows the user to update a field on the grid.

    It is very similar to an expense report where you have line items and the amount.

    Of course, there are other little needs, but I’m not able to find anything anywhere unless I dive “real” deep into flash.

    Have you seen anything that you could point me to?

    Much appreciated,

    Terry
    terry@iwearwatches.com

    Terry Middleton

    16 Aug 05 at 3:39 pm

  7. How would you do this using CF 7 and flash based cfforms? Is it possible?

    Steven Ross

    6 Sep 05 at 12:25 pm

  8. I am trying to use this code to sort the date field in my datagrid correctly and I am running into some problems. First of all, I cannot get the event handling function to execute unless I specify it in the mxml. Trying to create the event listener programmatically doesn’t seem to be working for me. Secondly, I can’t get the dataprovider to sort based on the custom funcitons. I am making a web service call to return the data and binding the result to the datagrid. Any suggestions for something I need to do differently. I am using the above code almost verbatim aside from the dataprovider being different.
    Thanks,
    Micah

    Micah

    19 Sep 05 at 9:27 am

  9. you are sorting the array that is assigned to the datagrid.dataprovider and not the datagrid itsself.
    I have a dataset holding a recordset. For display purposes I use a datagrid (datagrid.dataprovider=dataset.dataprovidider)
    When I try to sort the grid on a datefield by using datagrid.sortItems(compareFunc) the compareFunc is never called, as if the method does not exists.

    pitcher

    15 Nov 05 at 1:46 pm

  10. Why not simply manipulate the date/timestamp as milliseconds/Number and use a CustomCellRenderer on the table column to render the text? The table will do auto sorting based on the millisecond/Number value and not the rendered text (which is what we see). It’s much faster than a custom Comparator, especially with large datasets.

    The Date.class in AS provides all the methods needed to convert millis/timestamp to Date and vice versa and methods to create the formatted date text as needed.

    Carlos Lozano Diez

    15 Dec 05 at 10:07 am

  11. Dear All,

    I am experienced in flex 1.5 for the past 1 month. Now I am able to get results from remote objects and populate it to a Datagrid. Now I have an issue of adding these values to a Tree. For example:
    First set of values in array:
    1.Thomas
    2.James
    3.Philips

    Second set of values in array:
    1.java, unix, j2ee
    2. Flex, Flash, CF
    3. Oracle, Java

    I need to design a tree at runtime. when i click the node “Thomas”, I need to add the children for that node “java”,”unix”,”j2ee” and open the node and display it to the user.

    Any help? mail me to ship2moon@gmail.com

    Thanks in advance.

    regards,
    Logu.

    Logu

    6 Mar 06 at 9:18 pm

  12. I’ve got a major problem with the dataGrid in Flash 8.

    When used on the stage all works fine but once the dataGrid is nested in a movie clip the data displays and the listener is getting assigned but it returns null for selectedItem.

    Is there an issue when putting a datagrid nested into movie clips.

    Yavstr

    18 Dec 06 at 3:58 pm

  13. This function is a built-in sort function to flash and works on dates.

    my_dg.sortItemsBy(“Date”, Array.NUMERIC | Array.DESCENDING);

    Dre

    21 Jan 07 at 1:49 pm

  14. Thanks. That helps.
    And in dateFieldCompare(item1:Object, item2:Object, bit:Number), the input “bit” for order may be unnecessary.

    Armlias

    28 Dec 07 at 10:56 pm

  15. Hi,

    I have a requirement in which i have to implement paging and sorting together. Requirement is as follows.

    “Initially bind first 10 records from 5000 reocrds to the datagrid. On scrolling the scrollbar i need to bind another set of records and so on. Scrolling should be on done both upwards and downwards. i.e. when we go upwards we need to get previous set of records and downwards we need to get next set of records. Another requirement is I need to implement Server-Side Sorting on datagrid”.

    Can anyone help me in doing so?.

    Thanks in advance…

    vins

    22 Jun 08 at 10:48 pm

  16. This seems to work for one date column, but not when I have two date columns in the datagrid. any ideas?

    Core000

    9 Oct 09 at 6:16 am

Leave a Reply