9 Replies Latest reply on Jun 20, 2011 10:57 AM by synga

    Sorting a Collection with dynamic columns using a custom compare function for multiple columns

    synga

      I need help and ideas on how to sort a ListCollectionView.  My problem is complicated by 3 requirements-

           1. The column values contain HTML tags that needs to be removed before sorting (use custom compareFunction to strip HTML)

           2. The columns are dynamic, so dataField names are not known at compile time (need a single compareFunction for all columns)

           3. The data is used in an AdvancedDataGrid so multi-column sorting is required

       

      I have figured out how to solve any 2 of the 3 requirements.  However, I am having difficulties supporting all 3 requirements.

       

      Any help or ideas would be greatly appreciated.  Thanks.

        • 1. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
          brendalc1636

          Does this mean you solved 1 and 2 because there is an explanation in paranthesis after your description?

           

          The AdvancedDataGrid already has multi-column sorting built in so you shouldn't have to worry about that.

          • 2. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
            synga Level 1

            No.  Given any 2 of the 3 requirements, I can figure out a solution.  However, I am unable to solve all 3 requirements together.  Solutions (the ones I've tried) seem to conflict with each other.

             

            Solutions tried and problems encountered

            (req 1 & 2) Create Sort and SortField objects dynamically.  Assign the compareFunction dynamically in ActionScript.  (req 3) problem is for multi-column sort, the custom compareFunction does not know how to perform the compare.  Current column can be captured in headerRelease but multi-columns are problematic.

             

            (req 1 & 3) Each column will be assigned its own compareFunction.  (req 2) problem is dynamic columns prevents hard-coding dataField names in the custom compareFunction.  Therefore a generic compareFunction is needed.

             

            (req 2 & 3) AdvancedDataGrid handles dynamic columns and multi-column sort.  Columns are created in ActionScript.  No need for special sorting code.  (req 1) problem is data contains HTML tags that needs to be stripped before sorting.

            • 3. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
              synga Level 1

              After playing with this some more I think I've figured out a solution.  This seems to work in initial testing.  Also, there is not a need to capture the current sort column in the headerRelease event which many offered solutions suggested.  Another benefit to this solution is that keyboard initiated sorting is handled also.  Whereas the headerRelease event is only triggered by a mouse click on the column header and special handling is required if the user uses the keyboard to access the column header.

               

              One point that I don't understand is how ascending/decending order is determined.  Behavior seems to be different between a single SortField versus multiple SortFields.  Notice how the compareResults are handled for the different situations.  Anyone out there know why???

               

               

               

               

              private function colSortCompareFunction(obj1:Object, obj2:Object, fields:Array = null):int

              {

               

                   var compareResults:int = 0;

               

                   var newObj1:Object = new Object();

               

                   var newObj2:Object = new Object();

               

               

                   // should not be a condition that is met

               

               

               

               

                   if (_dataProviderDetails.sort.fields == null)

                   {

               

                        var s:Sort = new Sort();

               

                        var f:Function = s.compareFunction;

               

                        return f.call(null, obj1, obj2, fields);

                   }

               

                   // when a single column is selected for sorting

               

               

               

               

                   else if (_dataProviderDetails.sort.fields.length == 1)

                   {

               

                        var firstFld:SortField = _dataProviderDetails.sort.fields[0];

               

                        newObj1[firstFld.name] = stripHTML(obj1[firstFld.name]

              as String);

                        newObj2[firstFld.name] = stripHTML(obj2[firstFld.name]

              as String);

               

                        compareResults = ObjectUtil.compare(newObj1[firstFld.name], newObj2[firstFld.name]);

               

                        return compareResults;

                   }

               

                   // when multiple columns are selected for sorting

               

               

               

               

                   else

               

               

                   {

               

               

                        for each (var fld:SortField in _dataProviderDetails.sort.fields)

                        {

                             newObj1[fld.name] = stripHTML(obj1[fld.name]

              as String);

                             newObj2[fld.name] = stripHTML(obj2[fld.name]

              as String);

               

                             compareResults = ObjectUtil.compare(newObj1[fld.name], newObj2[fld.name]);

               

                             if (compareResults != 0)

                             {

               

                                  if (fld.descending)

                                  {

               

                                       return compareResults * -1;

                                  }

               

                                  else

               

               

                                  {

               

               

                                       return compareResults;

                                  }

                             }

                        }

               

               

                        return compareResults;

                   }

              }

               

               

               

               

               

               

              Does anyone see any problems with this solution?

               

               

              NOTE:  stripHTML(String) is a simple function using regular expression to remove HTML tags.

               

              Thx

               

              • 4. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
                synga Level 1

                After more testing, I found a flaw in the above solution.

                 

                I am unable to change the sort direction of a higher level sorted column.  For example, if I sorted by 'lastName', 'firstName', and 'age'.  I am unable to to change the sort direction (acending/decending) of 'lastName' or 'firstName'.

                 

                So I'm still looking for a solution.

                • 6. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
                  Flex harUI Adobe Employee

                  I'm not sure why you need to change the sort direction.  I would suggest

                  trying a subclass of AdvancedDataGridColumn that has the compare function as

                  a method.  Then it has the context of the column and can reference the given

                  dataField easily.  Then see what other problems occur.

                  • 7. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
                    synga Level 1

                    I don't need to change sort direction per se, but default AdvancedDataGrid behavior allows the user to do that.  I just want to perserve as much default ADG behavior as possible.

                     

                    When you say use a subclass of AdvancedDataGridColumn, are you suggesting to extend it and provide the sort sort column when the compareFunction is called?  Or is there a Flex class that already does this?

                     

                    If I need to extend AdvancedDataGridColumn, I don't know enough of the internals to override how/when/where the compareFunction is called.  Where can I learn these?  I haven't found any sources that explains the inner workings of this component.

                     

                    If I can reference the column in the compareFunction, I think my problems will be solved.

                     

                    Thanks

                    • 8. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
                      Flex harUI Adobe Employee

                      Here's my simplified analogy of your scenario.

                       

                      //I have a set of fields that I get from someplace:

                      Var columnFields:Array = ["firstName", "lastName"];

                       

                      //And I want to generate columns for those fields:

                      Var columns:Array = [];

                      For (var index:int = 0; index < columnFields.length; index++)

                      {

                          var col:AdvancedDataGridColumn = new

                      AdvancedDataGridColumn(columnFields[index]));

                          // and assign a custom compare function that uses that

                          // columnField

                          col.sortCompareFunction = ???

                          columns.push(col);

                      }

                      Adg.columns = column;

                       

                      I am suggesting subclassing AdvancedDataGridColumn

                       

                      Public class MyAdvancedDataGridColumn extends DataGridColumn

                      {

                          public function MyAdvancedDataGridColumn(dataField:String)

                          {

                              sortCompareFunction = mySortCompareFunction;

                          }

                       

                          public function mySortCompareFunction(obj1:Object, obj2:Object,

                      fields:Array = null)

                          {

                              // in this function, you can use 'obj1[dataField]' to

                              // access the field for this column

                              if (obj1[dataField] < obj2[dataField])

                                  return -1;

                              ...

                          }

                      }

                       

                      Then your loop would just look like:

                       

                      Var columns:Array = [];

                      For (var index:int = 0; index < columnFields.length; index++)

                      {

                          var col:AdvancedDataGridColumn = new

                      MyAdvancedDataGridColumn(columnFields[index]));

                          columns.push(col);

                      }

                      Adg.columns = column;

                      • 9. Re: Sorting a Collection with dynamic columns using a custom compare function for multiple columns
                        synga Level 1

                        I think that worked!!!  I'm going to play with it a little more but it's looking very good.  I will mark as "answered" if it holds up under our tests.

                         

                        You're a genius!

                         

                        Thank you.

                         

                        Regards.