12
Aug
07

Sorting date columns in a DataGrid

Here’s an example of sorting a column of dates in a Flex DataGrid. The dates start out as Strings (such as “04/14/1980″) so you create a custom sortCompareFunction on that DataGrid column which converts the strings to dates so Flex will sort the dates in sequential order (as oppsed to string order). Hope that helps somebody out there.

I also created a little tooltip on the date column which shows the dates in a somewhat more readable form (”April 14 1980″) using the DataGridColumn object’s showDataTips and dataTipFunction properties.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/12/sorting-date-columns-in-a-datagrid/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            import mx.utils.ObjectUtil;

            private function date_sortCompareFunc(itemA:Object, itemB:Object):int {
                /* Date.parse() returns an int, but
                   ObjectUtil.dateCompare() expects two
                   Date objects, so convert String to
                   int to Date. */
                var dateA:Date = new Date(Date.parse(itemA.dob));
                var dateB:Date = new Date(Date.parse(itemB.dob));
                return ObjectUtil.dateCompare(dateA, dateB);
            }

            private function date_dataTipFunc(item:Object):String {
                return dateFormatter.format(item.dob);
            }
        ]]>
    </mx:Script>

    <mx:ArrayCollection id="arrColl">
        <mx:source>
            <mx:Array>
                <mx:Object name="User A" dob="04/14/1980" />
                <mx:Object name="User B" dob="01/02/1975" />
                <mx:Object name="User C" dob="12/30/1977" />
                <mx:Object name="User D" dob="10/27/1968" />
            </mx:Array>
        </mx:source>
    </mx:ArrayCollection>

    <mx:DateFormatter id="dateFormatter" formatString="MMMM D, YYYY" />

    <mx:DataGrid id="dataGrid" dataProvider="{arrColl}">
        <mx:columns>
            <mx:DataGridColumn dataField="name"
                    headerText="Name:" />

            <mx:DataGridColumn dataField="dob"
                    headerText="Date of birth:"
                    sortCompareFunction="date_sortCompareFunc"
                    showDataTips="true"
                    dataTipFunction="date_dataTipFunc" />
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

View source is enabled in the following example.


23 Responses to “Sorting date columns in a DataGrid”


  1. 1 Theo Aug 12th, 2007 at 11:08 am

    I don’t quite see why the dates are strings in your data, why not use date objects to start with?

    Anyway, if you want you can sort the int’s returned by Date.parse like this:

    private function dateComparator( itemA : Object, itemB : Object ) : int {
        var a : int = Date.parse(itemA.dob);
        var b : int = Date.parse(itemB.dob);
    
        return (b - a)/Math.abs(b - a);
    }
    
  2. 2 peterd Aug 12th, 2007 at 2:35 pm

    Theo,

    The dates were strings instead of date objects, well, for no real reason. If they were dates to begin with, I believe they would have sorted properly without any additional code being needed. Although, if you were getting the data from an XML document or something else, its likely they would have imported as Strings.

    Also, looking again at the ObjectUtil documentation, it looks like I could have skipped converting to dates and used the ObjectUtil.numericCompare() method, or your code works great too.

    Good tip, thanks.

  3. 3 Theo Aug 13th, 2007 at 6:40 am

    No, dates aren’t sorted right by default. I’ve tried a few times and it always surprises me that DataGrid doesn’t support it by default, it’s such an obvious feature.

    I’m not sure why but they end up ordered in a way that looks quite random to me. I can imagine that they are ordered either by their toString value or some other date string format that doesn’t support ordering.

  4. 4 Charlie Aug 15th, 2007 at 4:32 pm

    I like to keep my dates in the database as YYYY-MM-DD, this way they sort without help. Then all you need is a labelFunction to display them as you like them.

  5. 5 sm Sep 20th, 2007 at 9:02 am

    how do u make this sort function generic i.e if you have many numeric columns in a datagrid, do you need to write a comparator function for each column?

  6. 6 peterd Sep 20th, 2007 at 12:09 pm

    sm,

    Not sure if there is a better way, but this was the first idea that came to mind. Surprisingly, it seems to work, based on my approximate 90 seconds of testing.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    
        <mx:Script>
            <![CDATA[
                import mx.utils.ObjectUtil;
    
                private var col:String;
    
                private function numericSort(itemA:Object, itemB:Object):int {
                    return ObjectUtil.numericCompare(itemA[col], itemB[col]);
                }
            ]]>
        </mx:Script>
    
        <mx:Array id="arr">
            <mx:Object name="one" col1="1" col2="0.59" col3="1.5" col4="40" />
            <mx:Object name="two" col1="2" col2="0.32" col3="1.1" col4="-12" />
            <mx:Object name="three" col1="3" col2="0.82" col3="2.9" col4="22" />
            <mx:Object name="four" col1="4" col2="0.29" col3="-0.2" col4="25" />
            <mx:Object name="five" col1="5" col2="0.33" col3="5.0" col4="37" />
            <mx:Object name="six" col1="6" col2="0.51" col3="-2.3" col4="-11" />
            <mx:Object name="seven" col1="7" col2="0.70" col3="4.1" col4="-9" />
        </mx:Array>
    
        <mx:DataGrid id="dataGrid"
                dataProvider="{arr}"
                headerRelease="col = dataGrid.columns[event.columnIndex].dataField;">
            <mx:columns>
                <mx:DataGridColumn dataField="name" />
                <mx:DataGridColumn dataField="col1"
                        sortCompareFunction="numericSort" />
                <mx:DataGridColumn dataField="col2"
                        sortCompareFunction="numericSort" />
                <mx:DataGridColumn dataField="col3"
                        sortCompareFunction="numericSort" />
                <mx:DataGridColumn dataField="col4"
                        sortCompareFunction="numericSort" />
            </mx:columns>
        </mx:DataGrid>
    
    </mx:Application>
    

    Hope that helps,
    Peter

  7. 7 sm Sep 20th, 2007 at 2:45 pm

    Thanks Peter!Actually I have a datagrid that is getting generated dynamically using actionscript. The sortcomparefunction seems to work when i put it in the mxml tag but when i try using it in actionscript it fails!
    eg if i do

    datagridcolumnname.sortCompareFunction = numericSort;
    

    in the mx:Script tags

  8. 8 peterd Sep 20th, 2007 at 3:06 pm

    sm,

    Does the following work for you? Note that I have a slight “workaround” where I’m storing the currently selected header by listening for the data grid control’s headerRelease event.

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white"
            creationComplete="init();">
    
        <mx:Script>
            <![CDATA[
                import mx.events.DataGridEvent;
                import mx.controls.dataGridClasses.DataGridColumn;
                import mx.controls.DataGrid;
                import mx.utils.ObjectUtil;
    
                private var dataGrid:DataGrid;
                private var col:String;
    
                private function init():void {
                    /* name column */
                    var nameCol:DataGridColumn = new DataGridColumn("name");
                    /* col1 column */
                    var col1Col:DataGridColumn = new DataGridColumn("col1");
                    col1Col.sortCompareFunction = numericSort;
                    /* col2 column */
                    var col2Col:DataGridColumn = new DataGridColumn("col2");
                    col2Col.sortCompareFunction = numericSort;
                    /* col3 column */
                    var col3Col:DataGridColumn = new DataGridColumn("col3");
                    col3Col.sortCompareFunction = numericSort;
                    /* col4 column */
                    var col4Col:DataGridColumn = new DataGridColumn("col4");
                    col4Col.sortCompareFunction = numericSort;
    
                    var cols:Array = [];
                    cols.push(nameCol);
                    cols.push(col1Col);
                    cols.push(col2Col);
                    cols.push(col3Col);
                    cols.push(col4Col);
    
                    dataGrid = new DataGrid();
                    dataGrid.dataProvider = arr;
                    dataGrid.columns = cols;
                    dataGrid.addEventListener(DataGridEvent.HEADER_RELEASE, dataGrid_headerRelease);
                    addChild(dataGrid);
                }
    
                private function dataGrid_headerRelease(evt:DataGridEvent):void {
                    col = dataGrid.columns[evt.columnIndex].dataField;
                }
    
                private function numericSort(itemA:Object, itemB:Object):int {
                    return ObjectUtil.numericCompare(itemA[col], itemB[col]);
                }
            ]]>
        </mx:Script>
    
        <mx:Array id="arr">
            <mx:Object name="one" col1="1" col2="0.59" col3="1.5" col4="40" />
            <mx:Object name="two" col1="2" col2="0.32" col3="1.1" col4="-12" />
            <mx:Object name="three" col1="3" col2="0.82" col3="2.9" col4="22" />
            <mx:Object name="four" col1="4" col2="0.29" col3="-0.2" col4="25" />
            <mx:Object name="five" col1="5" col2="0.33" col3="5.0" col4="37" />
            <mx:Object name="six" col1="6" col2="0.51" col3="-2.3" col4="-11" />
            <mx:Object name="seven" col1="7" col2="0.70" col3="4.1" col4="-9" />
        </mx:Array>
    
    </mx:Application>
    
  9. 9 sm Sep 21st, 2007 at 6:37 am

    Thanks a million Peter!!!u r a godsend!!that did work..i have been stuck on it fr 3 days and with such little examples on dynamic grids available online your help really meant a lot to me!!!

  10. 10 peterd Sep 21st, 2007 at 7:06 am

    Glad I could help. I also highly recommend subscribing to the FlexCoders mailing list, if you haven’t already. (see http://flex.org/community/#mailinglists for links and details on various Flex-related mailing lists)

    At over 7650 members, it is quite an active and informative list. Although one word of warning, it can get very busy (~3000 posts a month), so make sure you set up the appropriate filters otherwise your inbox can get a bit overwhelmed.

    Happy Flexing!
    Peter

  11. 11 sm Sep 21st, 2007 at 8:12 am

    Thanks. I definitely need a lot of information with Flex and m going to join this community right away!

  12. 12 DhanaLakshmi Jan 17th, 2008 at 4:18 am

    Thanks for the post. It is useful as the data I get from a webservice is in the form of string as u used.

  13. 13 Nikos Katsikanis Aug 28th, 2008 at 3:55 am

    This is super useful code dude :)

  14. 14 AM Dec 18th, 2008 at 10:00 pm

    Hi,

    I want to have a generic date_sortCompareFunc function for all the datagrid’s in my application. Is it possible to pass an extra parameter to this function. Basically I want to pass the object field on which the sort function should work.

    AM

  15. 15 Peter deHaan Dec 19th, 2008 at 3:00 pm

    AM,

    I don’t believe you can, since those parameters get passed from Flex. Although you may be able to extend DataGrid and/or DataGridColumn and add that functionality.
    You could try asking on the FlexCoders mailing list and see if anybody has some suggestions.

    Peter

  16. 16 jalal Feb 13th, 2009 at 8:58 am

    if we have a non standard date format:

    private function date_sortCompareFunc(itemA:Object, itemB:Object):int
    {
    return ObjectUtil.dateCompare(DateField.stringToDate(itemA.dob, “YYYY-MM-DD”), DateField.stringToDate(itemB.dob, “YYYY-MM-DD”));
    }/*

  17. 17 om Apr 16th, 2009 at 7:33 am

    If you have multiple numeric column to sort i think it is better to have something like that :

    /** The sort function */
    function numericSort(field:String):Function {
    return function (obj1:Object, obj2:Object):int {
    return ObjectUtil.numericCompare(obj1[field], obj2[field]);
    }

    And in your mxml for each numeric column :

  18. 18 om Apr 16th, 2009 at 7:36 am

    Hum bug because of the tags:

    So in your mxml :

    <mx:DataGridColumn dataField=”theFieldName” sortCompareFunction=”numericSort(’theFieldName’)” />

  19. 19 TE Jun 2nd, 2009 at 5:46 am

    Any way to do this type of sorting with Time-strings?

  20. 20 Vicki Jun 19th, 2009 at 11:21 am

    I used the date sorting example to sort one date field in my window but I have 10 more date fields in the same window and I would like to make those sortable as well. Do I need to create a seperate function for each date field or is there a way to create one function to handle all 11 date fields?

    Thanks,
    Vicki

  21. 21 Peter deHaan Jun 19th, 2009 at 5:06 pm

    Vicki,

    I believe since I hardcoded the dataField property (”dob”) in the sort function itself (date_sortCompareFunc()), you’d need 10 separate functions, although you could probably come up with a way to dynamically.

    In fact, I haven’t tried this solution personally, but you could try this: http://justinjmoses.wordpress.com/2008/03/11/generic-flex-datagrid-case-insensitive-sort/

    Peter

  22. 22 Vicki Jun 22nd, 2009 at 11:00 am

    Peter,

    Thanks but that’s just it, I didn’t want to create 10 seperate functions. I have a feeling this is the only way to do it, unfortunately. Since I am just starting out in Flex (this is my first project), I have no clue how to dynamically do this or anything yet. Thanks so much for responding though.

    Vicki

  23. 23 Peter deHaan Jun 22nd, 2009 at 12:10 pm

    Vicki,

    This should work: http://justinjmoses.wordpress.com/2008/03/11/generic-flex-datagrid-case-insensitive-sort/

    If not, let me know and we can try and take a look.

    Peter

Leave a Reply

This blog is terrible at eating HTML tags. If you plan on posting code/XML, please escape your "<" characters as "&lt;" and your ">" characters as "&gt;".




Badge Farm

  • Powered by Redoable 1.2
  • Cornify
  • Feeds burnt by Feedburner
  • Feed