Creating a custom sort on a DataGrid control in Flex

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.

6 thoughts on “Creating a custom sort on a DataGrid control in Flex

  1. 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

  2. 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

  3. 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?

  4. Hi peter,

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

Comments are closed.