0
votes

I have an AdvancedDatagrid with two columns: Code (strings), and Value (numbers). I use the same sort function for each column. What I want to do is to sort both columns based on the Value column (numeric data), but where there is no number available, I want the sorting to be done alphabetically for the Code column.

I have simplified the problem I am facing with an example to represent what I am trying to do:

The picture shows the two columns, with the sorting of both columns based on the Value column. Where the value is NaN, I want the Code column values to be sorted Alphabetically. So the One, Two, Three, Four would remain the same, but BADC would be ABCD.

enter image description here

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" 
                layout="absolute" minWidth="955" minHeight="600" initialize="initializeHandler(event)">

    <mx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.FlexEvent;
            import mx.utils.ObjectUtil;

            [Bindable]
            private var ac:ArrayCollection;

            protected function initializeHandler(event:FlexEvent):void
            {
                ac = new ArrayCollection();

                var one:NameValueObject = new NameValueObject("One", 1);
                var two:NameValueObject = new NameValueObject("Two", 2);
                var three:NameValueObject = new NameValueObject("Three", 3);
                var four:NameValueObject = new NameValueObject("Four", 4);
                var a:NameValueObject = new NameValueObject("A", NaN);
                var b:NameValueObject = new NameValueObject("B", NaN);
                var c:NameValueObject = new NameValueObject("C", NaN);
                var d:NameValueObject = new NameValueObject("D", NaN);

                ac.addItem(one);
                ac.addItem(two);
                ac.addItem(three);
                ac.addItem(four);
                ac.addItem(b);
                ac.addItem(a);
                ac.addItem(d);
                ac.addItem(c);              
            }

            private function numericValueSort(obj1:Object, obj2:Object):int
            {
                var value1:Number = (obj1 as NameValueObject).value;
                var value2:Number = (obj2 as NameValueObject).value;

                return ObjectUtil.numericCompare(value1, value2);
            }

            private function codeLabelFunction(item:Object, column:AdvancedDataGridColumn):String
            {
                return (item as NameValueObject).code;
            }

        ]]>
    </mx:Script>

    <mx:AdvancedDataGrid width="500" height="300" dataProvider="{ac}">
        <mx:columns>
            <mx:AdvancedDataGridColumn id="codeColumn" 
                                       headerText="Code"
                                       dataField="value"
                                       labelFunction="codeLabelFunction"
                                       sortCompareFunction="numericValueSort">

            </mx:AdvancedDataGridColumn>
            <mx:AdvancedDataGridColumn id="numericValueColumn" 
                                       headerText="Value"
                                       dataField="value"
                                       sortCompareFunction="numericValueSort">

            </mx:AdvancedDataGridColumn>
        </mx:columns>
    </mx:AdvancedDataGrid>
</mx:Application>

The NaveValueObject class

package
{
    public class NameValueObject
    {
        public var code:String;
        public var value:Number;

        public function NameValueObject(aCode:String, aNumber:Number)
        {
            code = aCode;
            value = aNumber;
        }
    }
}
4
Why do you sort your code column with numericValueSort?Joe Taras
In the actual application that I am working on, the two columns in question use the same sort compareDrenai
Hi, check my answer and tell me if it's ok ;)Joe Taras
Added the approach I used as an answer below, thanks for responsesDrenai

4 Answers

1
votes

Try this:

private function numericValueSort(obj1:Object, obj2:Object):int
{
    var o1:NameValueObject = obj1 as NameValueObject;
    var o2:NameValueObject = obj2 as NameValueObject;

    var ret:int = 0;
    if (isNaN(o1.value) || isNaN(o2.value)) {
        if (o1.code > o2.code) {
            ret = 1;
        } else if (o1.code < o2.code){
            ret = -1;
        }
    } else {
        ret = ObjectUtil.numericCompare(o1.value, o2.value);
    }
    return ret;
}

Your function process number is either are valued, also comparation is between code field of two objects

0
votes

The following compare function will give priority to numeric values and sort NaN values based on the codes. The approach is to compose a new string for each object and prefix the string with a value indicating the priority (A > B):

private function numericValueSort(obj1:NameValueObject, obj2:NameValueObject):int {
  var a:String = (isNaN(obj1.value) ? "B" : "A") + obj1.value + obj1.code;
  var b:String = (isNaN(obj2.value) ? "B" : "A") + obj2.value + obj2.code;
  return ObjectUtil.stringCompare(a, b);
}

Note that this might give strange results when sorting 1, 2, 11 for instance. In that case you're better of using a natural compare. There is an ActionScript immplementation available in the AS3Commons Lang library.

0
votes

I figured it out, and this is the sortCompareFunction I ended up using:

It checks for the 3 possible conditions of a value/s being invalid. If the only one is NaN, returns 1 or -1, otherwise does a sort based on the code column.

Then if both values are valid (not NaN), does a regualar compare:

private function numericValueSort(obj1:Object, obj2:Object):int
{
    var o1:NameValueObject = obj1 as NameValueObject;
    var o2:NameValueObject = obj2 as NameValueObject;

    if( isNaN(o1.value) && !isNaN(o2.value) ){
        return 1; // o1 appears after o2;
    }
    if( !isNaN(o1.value) && isNaN(o2.value) ){
        return -1; // o1 appears before o2
    }
    if( isNaN(o1.value) && isNaN(o2.value) ){
            // Both values are NaN, so they will have been placed 
            // at the end when compared with valid values (from previous two 
            // IF statements, but now to compare to each other, we sort using the 
            // code field
        return ObjectUtil.stringCompare(o1.code, o2.code);
    }
    // If neither value is NaN, then do a regular numeric compare
    return ObjectUtil.numericCompare(o1.value, o2.value);
}

enter image description here

0
votes

I want all the NaN values to be at the bottom, irrespective of the sorting. Other than Nan values it should be sorted(keeping all the NaN values at the bottom)?