0

I am trying to sort an XMLListCollection based upon another XMLListCollection's attributes and I am not having much success.

I would like to sort a collection of food into the order in which it was eaten - which is stored in another XMLListcollection.

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
xmlns:fx="http://ns.adobe.com/mxml/2009" 
xmlns:s="library://ns.adobe.com/flex/spark" 
xmlns:mx="library://ns.adobe.com/flex/mx" 
minWidth="955" minHeight="600">
<fx:Declarations>
    <fx:XML xmlns="" id="_foods">
        <data>
            <node label="Apple" id="A"/>
            <node label="Banana" id="B"/>
            <node label="Carrot" id="C"/>
            <node label="Dandelion" id="D"/>
        </data>
    </fx:XML>
    <fx:XML xmlns="" id="_orders">
        <data>
            <order  id="C"/>
            <order  id="A"/>
            <order  id="D"/>
            <order  id="B"/>
        </data>
    </fx:XML>
    <s:XMLListCollection id="_orderList" source=" {_orders.children()}"/>
    <s:XMLListCollection id="_foodCollection"   source="{_foods.children()}" sort="{_foodSort}"/>
    <s:Sort id="_foodSort" compareFunction="sortFruits"/>
</fx:Declarations>
<fx:Script>
    <![CDATA[

        protected function sortFruits(a:Object, b:Object, fields:Array = null):int
        {
         var _currentItem:XML = XML(a);
         var _currentOrderIndex:int= getNodeIndexByAttribute(_orderList,'id',_currentItem.@id);
            var _currentFruitIndex:int= getNodeIndexByAttribute(_foodCollection,'id',_currentItem.@id)

            if(_currentFruitIndex > _currentOrderIndex) {_returnData =1;}
            else 
            if(_currentFruitIndex < _currentOrderIndex) { _returnData =-1;}
            else {_returnData = 0}

            var _returnData:int = 0
                return _returnData
        }

        public function getNodeIndexByAttribute(theCollection:XMLListCollection,theAttributeName:String, theAttributeValue:String):int { 
            //THIS IS RETURNS THE INDEX OF A CHILD NODE BASED UPON AN ATTRIBUTE THAT IS PASSED IN - GENERIC FUNCTION
            var _returnData:int 

            for (var i:int = 0; i < theCollection.length; i++) 
            {
                var _currentItem:XML = theCollection.getItemAt(i) as XML
                if (_currentItem.attribute(theAttributeName) == theAttributeValue)  { _returnData = i;
        break;
                }

            }


            return _returnData;
        } 
    ]]>
</fx:Script>
<s:List width="100%" height="100%" labelField="@label" dataProvider="{_foodCollection}"/>
</s:Application>

I seem to be doing everything right as far as I can see but I must be doing something wrong as it doesnt work! I think it may have something to do with how I have implemented the compare function.

Any help with this would be greatly appreciated! ;)

zero323
  • 322,348
  • 103
  • 959
  • 935
Beaker
  • 214
  • 1
  • 4
  • 16

1 Answers1

1

By defining a sort function the XMLListCollection will not be sorted by default. You need to refresh() the collection at some point, this can be done automatically when you finish loading the view, or on-demand. I've added a button to illustrate the point.

If you test this button I've added, it should work. Also, I've replaced the s:sort by mx because I'm on an older Flex Framework, so feel free to change it again.

<?xml version="1.0" encoding="utf-8"?>
<s:Application
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx"
    >

<s:layout>
    <s:VerticalLayout />
</s:layout>

<fx:Declarations>

    <mx:Sort id="sort" compareFunction="sortFruits" />

    <fx:XML xmlns="" id="_foods">
        <data>
            <node label="Apple" id="A"/>
            <node label="Banana" id="B"/>
            <node label="Carrot" id="C"/>
            <node label="Dandelion" id="D"/>
        </data>
    </fx:XML>
    <fx:XML xmlns="" id="_orders">
        <data>
            <order id="C"/>
            <order id="A"/>
            <order id="D"/>
            <order id="B"/>
        </data>
    </fx:XML>
    <s:XMLListCollection id="_orderList" source=" {_orders.children()}"/>
    <s:XMLListCollection id="_foodCollection" source="{_foods.children()}" sort="{sort}"/>
</fx:Declarations>


<fx:Script>
<![CDATA[
    protected function sortFruits(a:Object, b:Object, fields:Array = null):int {
        var _currentItem:XML = XML(a);
        var _currentOrderIndex:int = getNodeIndexByAttribute(_orderList, 'id', _currentItem.@id);
        var _currentFruitIndex:int = getNodeIndexByAttribute(_foodCollection, 'id', _currentItem.@id)

        if (_currentFruitIndex > _currentOrderIndex) {
            _returnData = 1;
        }
        else if (_currentFruitIndex < _currentOrderIndex) {
            _returnData = -1;
        }
        else {
            _returnData = 0
        }

        var _returnData:int = 0
        return _returnData
    }

    public function getNodeIndexByAttribute(theCollection:XMLListCollection, theAttributeName:String, theAttributeValue:String):int {
        //THIS IS RETURNS THE INDEX OF A CHILD NODE BASED UPON AN ATTRIBUTE THAT IS PASSED IN - GENERIC FUNCTION
        var _returnData:int

        for (var i:int = 0; i < theCollection.length; i++) {
            var _currentItem:XML = theCollection.getItemAt(i) as XML
            if (_currentItem.attribute(theAttributeName) == theAttributeValue) {
                _returnData = i;
                break;
            }

        }


        return _returnData;
    }
    ]]>
</fx:Script>
    <s:List width="100%" labelField="@label" dataProvider="{_foodCollection}"/>
    <s:Button label="Sort me" click="_foodCollection.refresh()" />
</s:Application>
bitoiu
  • 6,893
  • 5
  • 38
  • 60
  • Hi bitoiu, thanks for taking a look. The good news is that some sorting occurs, however the bad news is that the sort is in the wrong order. In the example the expected result is C,A,D,B, but the actual result is C,B,A,D. Any other ideas? – Beaker Aug 06 '13 at 18:30
  • At this point you should debug the sorting code, I believe I've answered your question as why the sorting did not happen in the first place. If you breakpoint the compare function it should be obvious why the result is not the expected. Please mark the question as answered on my previous post, if you think I've helped you determine why sorting was not happening. – bitoiu Aug 06 '13 at 22:24
  • Hi bitoiu, If I could give you credit for taking time to look, I would, but unfortunately I cannot mark this question as answered as it is not. The problem is to sort a collection of food into the order in which it was eaten. The refresh was useful in this example (my actual code contains a refresh already) however I have already mentioned that I think the problem lies in how I implement the compare function. Debugging through the compare function shows me that it returns good data (-1 for move down, 0 to remain and 1 to move up) yet the the items do not sort themselves correctly. – Beaker Aug 07 '13 at 08:46