Flex DataGrid: sorting of non English alphabet data

27.11.2012.

The Table component is one of the most usable component in all GUI application frameworks. In the case of Flex framework the table structure is presented with the DataGrid component. The DataGrid component provides many built in features like sorting, resizing, customizing column layout, pagination, custom item rendering for columns and many others. DataGrid sorting mechanism can be defined in the following ways:

  • Using DataGrid sortableColumns property that enables sorting of the DataGrid column by clicking on the column headings. The default for this property is true.
  • Using DataGridColumn sortable property that enables sorting of an individual column. The default for this property is true.
  • Using DataGridColumn sortCompareFunction property that lets you specify a custom comparison function used for sorting of that column. This property lets you specify the function that compares two objects and determines which would be higher in the sort order.

Here is an example of using  DataGridColumn sortCompareFunction  property for sorting a column of dates presented as Strings in format “19/07/1984”. Custom sortCompareFunction on that DataGrid column will convert the strings to dates and Flex will sort the dates in sequential order:

<mx:Script>
        <![CDATA[
            import mx.utils.ObjectUtil;
            private function date_sortCompareFunc(itemA:Object, itemB:Object):int {
                var dateA:Date = new Date(Date.parse(itemA.dateOfBirth));
                var dateB:Date = new Date(Date.parse(itemB.dateOfBirth));
                return ObjectUtil.dateCompare(dateA, dateB);
            }  ]]>
    </mx:Script>
    <mx:ArrayCollection id="dataCollection">
        <mx:source>
            <mx:Array>
                <mx:Object name="Oreč" dateOfBirth ="04/14/1980" />
                <mx:Object name="Hunjet" dateOfBirth ="01/02/1975" />
                <mx:Object name="Žmak" dateOfBirth ="12/30/1977" />
                <mx:Object name=" Ćorić " dateOfBirth ="12/30/1977" />
                <mx:Object name=" Vori " dateOfBirth ="12/30/1977" />
                <mx:Object name="Grbac" dateOfBirth ="10/27/1968" />
            </mx:Array>
        </mx:source>
    </mx:ArrayCollection>
      <mx:DataGrid id="dataGrid" dataProvider="{dataCollection}">
        <mx:columns>
            <mx:DataGridColumn dataField="name" headerText="Name:" />
            <mx:DataGridColumn dataField="dateOfBirth" headerText="Date:"
                    sortCompareFunction="date_sortCompareFunc" />
        </mx:columns>
    </mx:DataGrid>

But what if you need to sort the DataGrid column data that contains non English alphabet (for example Croatian alphabet) or special characters? Sorting by column name using default DataGrid sorting mechanism in this example is displayed in the following picture: 

Flex uses ObjectUtil.stringCompare (a:String, b:String, caseInsensitive: Boolean = false) method that compares two string objects based on the position in the English alphabet. Following this logic we created a custom StringUtil all-static class that has the static ArrayCollection of Croatian letters (for our needs) and static method compareStrings that compares two string objects based on the position in the given ArrayCollection

public class SortUtil
{
    // Defined new alphabet to sort over
   public static var croatianLettersAC:ArrayCollection = new ArrayCollection([
        "A","a","B","b","C","c","Č","č","Ć","ć",
        "D","d","DŽ","dž","Đ","đ","E","e","F","f","G","g","H","h","I","i",
        "J","j","K","k","L","l","Lj","lj","M","m","N","n","Nj","nj","O","o",
        "P","p","Q","q","R","r","S","s","Š","š","T","t","U","u","V","W","w",
        "X","x","Y","y","v","Z","z","Ž","ž"]);
    public static function compareStrings(a:String, b:String):int
    {
        var len_a:int = a.length;
        var len_b:int = b.length;
        var char_a:String;
        var char_b:String;
   
        var val_a:Number;
        var val_b:Number;
      
        for(var i:int = 0; i < len_a && i < len_b; i++)
        {
            char_a = a.charAt(i);
            char_b = b.charAt(i);
          
            val_a = croatianLettersAC.getItemIndex(char_a);
            val_b = croatianLettersAC.getItemIndex(char_b);
  
            if(isNaN(val_a)) {
                val_a = char_a.charCodeAt(0);
            }
            if(isNaN(val_b)) {
                val_b = char_b.charCodeAt(0);
            }   
            if(val_a < val_b) {
                return -1;
            } else if(val_a > val_b) {
                return 1;
            } else {
                continue;
            }
        }
       // both strings are equal and in this case the shorter one must sort first
        if(len_a < len_b) {
            return -1;
        } else if(len_a > len_b) {
            return 1;
        } else {
            return 0;
        }
    }
}

To integrate this sorting mechanism into the DataGrid component we extended DataGridColumn class by adding the custom sortCompareFunction that uses SortUtil.compareStrings method for sorting the string data of DataGrid columns:

public class DataGridColumnCustom extends DataGridColumn
{
    public function DataGridColumnCustom(columnName:String=null)
    {
        sortCompareFunction = sortDefaultFunction; 
        super(columnName); 
    }
    public function sortDefaultFunction(obj1:Object, obj2:Object):int
    {
        var field:String = null;
        field = this.dataField;

      
        var a:String = "";
        var b:String = "";

      
        if(obj1[field] != null)
        {
            a = obj1[field].toString();
        }
        if(obj2[field] != null)
        {
            b = obj2[field].toString();
        }
        return SortUtil.compareStrings(a, b);
    }
}

Finally we get DataGrid component that sorts data in Croatian alphabet: 

<mx:DataGrid id="dataGrid" dataProvider="{dataCollection}">       
        <mx:columns>
            <component:DataGridColumnCustom dataField="name" headerText="Name:" />
            <mx:DataGridColumn dataField="dateOfBirth" headerText="Date:"
                    sortCompareFunction="date_sortCompareFunc" />
        </mx:columns>
    </mx:DataGrid>

Now the rows are sorted according to the national character set: