The following example shows how you can create a custom sort on a Flex DataGrid control by using the SortField class and creating a custom compare function.

Full code after the jump.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/04/09/creating-a-custom-sort-on-a-datagrid-control-in-flex/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
        layout="vertical"
        verticalAlign="middle"
        backgroundColor="white">

    <mx:Script>
        <![CDATA[
            import mx.collections.SortField;
            import mx.collections.Sort;
            import mx.controls.dataGridClasses.DataGridColumn;
            import mx.utils.ObjectUtil;

            private function sortOld():void {
                var sortField:SortField = new SortField();
                sortField.compareFunction = test2_compareFunc;
                sortField.descending = checkBox.selected;

                var oldSort:Sort = new Sort();
                oldSort.fields = [sortField];

                xmlListColl.sort = oldSort;
                xmlListColl.refresh();
            }

            private function sortNew():void {
                var sortField:SortField = new SortField();
                sortField.compareFunction = test3_compareFunc;
                sortField.descending = checkBox.selected;

                var sort:Sort = new Sort();
                sort.fields = [sortField];

                xmlListColl.sort = sort;
                xmlListColl.refresh();
            }

            private function resetSort():void {
                xmlListColl.sort = null;
                xmlListColl.refresh();
            }

            private function dataGridCol_labelFunc(item:XML, col:DataGridColumn):String {
                return item.*.(@name == col.dataField).text();
            }

            private function test2_compareFunc(itemA:XML, itemB:XML):int {
                var valueA:String = itemA.test2.text();
                var valueB:String = itemB.test2.text();
                return ObjectUtil.stringCompare(valueA, valueB);
            }

            private function test3_compareFunc(itemA:XML, itemB:XML):int {
                var valueA:String = itemA.test3.text();
                var valueB:String = itemB.test3.text();
                return ObjectUtil.stringCompare(valueA, valueB);
            }
        ]]>
    </mx:Script>

    <mx:XML id="tests" source="tests.xml" />
    <mx:XMLListCollection id="xmlListColl" source="{tests.test}" />

    <mx:ApplicationControlBar dock="true">
        <mx:CheckBox id="checkBox" label="descending:" labelPlacement="left" />

        <mx:Button label="Sort 'old'"
                click="sortOld();" />

        <mx:Button label="Sort 'new'"
                click="sortNew();" />

        <mx:Button label="Reset sort"
                click="resetSort();" />
    </mx:ApplicationControlBar>

    <mx:DataGrid id="dataGrid"
            dataProvider="{xmlListColl}"
            width="300"
            verticalScrollPolicy="on"
            sortableColumns="true">
        <mx:columns>
            <mx:DataGridColumn dataField="old"
                    labelFunction="dataGridCol_labelFunc"
                    sortCompareFunction="test2_compareFunc" />
            <mx:DataGridColumn dataField="new"
                    labelFunction="dataGridCol_labelFunc"
                    sortCompareFunction="test3_compareFunc"  />
        </mx:columns>
    </mx:DataGrid>

</mx:Application>

tests.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2008/04/09/creating-a-custom-sort-on-a-datagrid-control-in-flex/ -->
<tests>
    <test name="group1">
        <test2 name="old">One (old)</test2>
        <test3 name="new">Un (new)</test3>
    </test>
    <test name="group2">
        <test2 name="old">Two (old)</test2>
        <test3 name="new">Deux (new)</test3>
    </test>

    <test name="group8">
        <test2 name="old">Eight (old)</test2>
        <test3 name="new">Huit (new)</test3>
    </test>
</tests>

View source is enabled in the following example.

 
About The Author

Peter deHaan

Peter deHaan currently works for Adobe on the Flex SDK QA team. While not working on Flex, Flash, and ColdFusion applications, Peter enjoys making up bios and writing in 3rd person. Peter's rarely updated blog can be found at blogs.adobe.com/pdehaan/, actionscriptexamples.com, airexamples.com, and coldfusionexamples.com.

6 Responses to Creating a custom sort on a DataGrid control in Flex

  1. Dave says:

    Thanks! this is very useful info!!
    How can sorting a datagrid be accomplished using a ComboBox?

    Dave

  2. peterd says:

    Dave,

    A bit crude, but this should work:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white">
    
        <mx:Script>
            <![CDATA[
                import mx.events.ListEvent;
                import mx.collections.SortField;
                import mx.collections.Sort;
                import mx.controls.dataGridClasses.DataGridColumn;
                import mx.utils.ObjectUtil;
    
                private function comboBox_change(evt:ListEvent):void {
                    var field:String = comboBox.selectedItem.sortField;
                    var desc:Boolean = (comboBox.selectedItem.descending);
    
                    var sort:Sort = new Sort();
                    var sortField:SortField = new SortField();
                    sortField.descending = desc;
                    switch (field) {
                        case "old":
                            sortField.compareFunction = test2_compareFunc;
                            break;
                        case "new":
                            sortField.compareFunction = test3_compareFunc;
                            break;
                    }
                    sort.fields = [sortField];
                    xmlListColl.sort = sort;
                    xmlListColl.refresh();
                }
    
                private function resetSort():void {
                    xmlListColl.sort = null;
                    xmlListColl.refresh();
                }
    
                private function dataGridCol_labelFunc(item:XML, col:DataGridColumn):String {
                    return item.*.(@name == col.dataField).text();
                }
    
                private function test2_compareFunc(itemA:XML, itemB:XML):int {
                    var valueA:String = itemA.test2.text();
                    var valueB:String = itemB.test2.text();
                    return ObjectUtil.stringCompare(valueA, valueB);
                }
    
                private function test3_compareFunc(itemA:XML, itemB:XML):int {
                    var valueA:String = itemA.test3.text();
                    var valueB:String = itemB.test3.text();
                    return ObjectUtil.stringCompare(valueA, valueB);
                }
            ]]>
        </mx:Script>
    
        <mx:XML id="tests" source="tests.xml" />
        <mx:XMLListCollection id="xmlListColl" source="{tests.test}" />
    
        <mx:Array id="arr">
            <mx:Object label="Sort 'old' ascending"
                    sortField="old"
                    descending="false" />
            <mx:Object label="Sort 'old' descending"
                    sortField="old"
                    descending="true" />
            <mx:Object label="Sort 'new' ascending"
                    sortField="new"
                    descending="false" />
            <mx:Object label="Sort 'new' descending"
                    sortField="new"
                    descending="true" />
        </mx:Array>
    
        <mx:ApplicationControlBar dock="true">
            <mx:ComboBox id="comboBox"
                    dataProvider="{arr}"
                    change="comboBox_change(event);" />
    
            <mx:Button label="Reset sort"
                    click="resetSort();" />
        </mx:ApplicationControlBar>
    
        <mx:DataGrid id="dataGrid"
                dataProvider="{xmlListColl}"
                width="300"
                verticalScrollPolicy="on"
                sortableColumns="true">
            <mx:columns>
                <mx:DataGridColumn dataField="old"
                        labelFunction="dataGridCol_labelFunc"
                        sortCompareFunction="test2_compareFunc" />
                <mx:DataGridColumn dataField="new"
                        labelFunction="dataGridCol_labelFunc"
                        sortCompareFunction="test3_compareFunc"  />
            </mx:columns>
        </mx:DataGrid>
    
    </mx:Application>
    

    Looking back on the code, you may be able to move the sortField.compareFunction logic into the ComboBox data provider array instead of using a switch statement in the comboBox_change() function. I didn’t think of that the first time. You may also want to set the prompt property on the ComboBox.

    Peter

  3. peterd says:

    Something like this:

    <?xml version="1.0" encoding="utf-8"?>
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="vertical"
            verticalAlign="middle"
            backgroundColor="white">
    
        <mx:Script>
            <![CDATA[
                import mx.events.ListEvent;
                import mx.collections.SortField;
                import mx.collections.Sort;
                import mx.controls.dataGridClasses.DataGridColumn;
                import mx.utils.ObjectUtil;
    
                private function comboBox_change(evt:ListEvent):void {
                    var item:Object = comboBox.selectedItem;
    
                    var sortField:SortField = new SortField();
                    sortField.descending = item.descending;
                    sortField.compareFunction = item.compareFunc;
    
                    var sort:Sort = new Sort();
                    sort.fields = [sortField];
    
                    xmlListColl.sort = sort;
                    xmlListColl.refresh();
                }
    
                private function resetSort():void {
                    xmlListColl.sort = null;
                    xmlListColl.refresh();
                }
    
                private function dataGridCol_labelFunc(item:XML,
                            col:DataGridColumn):String {
                    return item.*.(@name == col.dataField).text();
                }
    
                private function test2_compareFunc(itemA:XML, itemB:XML):int {
                    var valueA:String = itemA.test2.text();
                    var valueB:String = itemB.test2.text();
                    return ObjectUtil.stringCompare(valueA, valueB);
                }
    
                private function test3_compareFunc(itemA:XML, itemB:XML):int {
                    var valueA:String = itemA.test3.text();
                    var valueB:String = itemB.test3.text();
                    return ObjectUtil.stringCompare(valueA, valueB);
                }
            ]]>
        </mx:Script>
    
        <mx:XML id="tests" source="tests.xml" />
        <mx:XMLListCollection id="xmlListColl" source="{tests.test}" />
    
        <mx:Array id="arr">
            <mx:Object label="Sort 'old' ascending"
                    sortField="old"
                    descending="false"
                    compareFunc="{test2_compareFunc}" />
            <mx:Object label="Sort 'old' descending"
                    sortField="old"
                    descending="true"
                    compareFunc="{test2_compareFunc}" />
            <mx:Object label="Sort 'new' ascending"
                    sortField="new"
                    descending="false"
                    compareFunc="{test3_compareFunc}" />
            <mx:Object label="Sort 'new' descending"
                    sortField="new"
                    descending="true"
                    compareFunc="{test3_compareFunc}" />
        </mx:Array>
    
        <mx:ApplicationControlBar dock="true">
            <mx:ComboBox id="comboBox"
                    dataProvider="{arr}"
                    prompt="Please select a sort..."
                    change="comboBox_change(event);" />
    
            <mx:Button label="Reset sort"
                    click="resetSort();" />
        </mx:ApplicationControlBar>
    
        <mx:DataGrid id="dataGrid"
                dataProvider="{xmlListColl}"
                width="300"
                verticalScrollPolicy="on"
                sortableColumns="true">
            <mx:columns>
                <mx:DataGridColumn dataField="old"
                        labelFunction="dataGridCol_labelFunc"
                        sortCompareFunction="test2_compareFunc" />
                <mx:DataGridColumn dataField="new"
                        labelFunction="dataGridCol_labelFunc"
                        sortCompareFunction="test3_compareFunc"  />
            </mx:columns>
        </mx:DataGrid>
    
    </mx:Application>
    

    Peter

  4. Sunny says:

    Thany you for your code.
    First I click the DataGrid’s header, there’s a small black triangle to show where it is working on.
    Then I click the buttons upside, to resort the DataGrid. Can the small black triangle change the meantime?

  5. Dave says:

    Thanks Peter, this is awesome!!

  6. Tahir Azeem Alvi says:

    Hi peter,

    What is the event that gets fired when you click on a datagrid column to sort it?