2009-09-02 3 views
8

OK, ich sortiere eine XMLListCollection in alphabetischer Reihenfolge. Ich habe jedoch ein Problem. Wenn der Wert "ALL" ist, möchte ich, dass er in der Liste zuerst steht. In den meisten Fällen geschieht dies bereits, aber Werte, die Zahlen sind, werden vor "ALL" sortiert. Ich möchte "ALL" immer die erste Auswahl in meinem DataProvider sein und dann den Rest alphabetisch.Flex: Sort - Eine benutzerdefinierte compareFunction schreiben?

Also versuche ich meine eigene Sortierfunktion zu schreiben. Gibt es eine Möglichkeit, dass ich überprüfen kann, ob einer der Werte alle ist, und wenn nicht, sage ihm, den regulären Vergleich der Werte zu machen?

Hier ist, was ich habe:

function myCompare(a:Object, b:Object, fields:Array = null):int 
{ 
    if(String(a).toLowerCase() == 'all') 
    { 
     return -1; 
    } 
    else 
     if(String(b).toLowerCase() == 'all') 
     { 
      return 1; 
     } 
    // NEED to return default comparison results here? 
} 

//------------------------------ 

var sort:Sort = new Sort(); 
sort.compareFunction = myCompare; 

Gibt es eine Lösung für das, was ich tun möchte?

+0

Was ist, wenn beide "alle" sind? –

+0

Ich würde gerne sagen, dass das nie passieren würde. Aber ja ich weiß das ist nie der Fall lol. Ich werde eine weitere if-Anweisung vor der Hand hinzufügen, um zu überprüfen, ob sie identisch sind, und return 0 ist wahr. Vielen Dank. –

Antwort

8

Nun habe ich etwas ausprobiert, und ich bin wirklich überrascht, dass es tatsächlich funktioniert hat, aber hier ist was ich getan habe.

Die Klasse Sort hat eine private Funktion namens internalCompare. Da es privat ist, kann man es nicht anrufen. ABER gibt es eine Getter-Funktion namens compareFunction, und wenn keine Vergleichsfunktion definiert ist, gibt sie einen Verweis auf die Funktion internalCompare zurück. Also habe ich diese Referenz bekommen und sie dann genannt.

private function myCompare(a:Object, b:Object, fields:Array = null):int 
{ 
    if(String(a).toLowerCase() == 'all') 
    { 
     return -1; 
    } 
    else if(String(b).toLowerCase() == 'all') 
    { 
     return 1; 
    } 
    // NEED to return default comparison results here? 
    var s:Sort = new Sort(); 
    var f:Function = s.compareFunction; 
    return f.call(null,a,b,fields); 
} 
+1

Sie können auch eine Instanz oder ein statisches Member der Klasse erstellen, sodass Sie nicht jedes Mal, wenn ein Vergleich durchgeführt wird, eine neue Sortierung erstellen müssen. –

+0

@Kathy, guter Punkt. –

+0

schön, gutes Schmuckstück :) – Tox

14

Die Lösung von John Isaacks ist genial, aber er vergaß über "Felder" Variable und sein Beispiel für kompliziertere Objekte nicht (anders als Strings)

Beispiel arbeiten:

// collection with custom objects. We want to sort them on "value" property 
// var item:CustomObject = new CustomObject(); 
// item.name = 'Test'; 
// item.value = 'Simple Value'; 

var collection:ArrayCollection = new ArrayCollection(); 
var s:Sort = new Sort(); 
s.fields = [new SortField("value")]; 
s.compareFunction = myCompare; 
collection.sort = s; 
collection.refresh(); 

private function myCompare(a:Object, b:Object, fields:Array = null):int 
{ 
    if(String((a as CustomObject).value).toLowerCase() == 'all') 
    { 
     return -1; 
    } 
    else if(String((b as CustomObject).value).toLowerCase() == 'all') 
    { 
     return 1; 
    } 
    // NEED to return default comparison results here? 
    var s:Sort = new Sort(); 
    s.fields = fields; 
    var f:Function = s.compareFunction; 
    return f.call(null,a,b,fields); 
} 
+0

Auf den ersten Blick dachte ich, du liegst falsch, aber stellt sich heraus, Adobe schaffte es wieder einmal zu vermasseln. Ihre internalCompare-Funktion sucht nach den Instanzfeldern anstelle des Funktionsparameters. Noch einer von Adobes Edelsteinen ... –

+0

Das war sehr hilfreich. Ich habe stattdessen versucht, String.localeCompare() zu verwenden, aber das hat einige unangenehme Nebenwirkungen, wenn das Sortieren zu oft aufgerufen wird –

0

Danke Jungs, das hat sehr geholfen. In unserem Fall benötigten wir alle leeren Zeilen (in einem DataGrid) auf der Unterseite. Alle nicht leeren Zeilen sollten normal sortiert sein. Unsere Zeilendaten sind alle dynamischen Objekte (aus JSON konvertiert) - der Aufruf von ValidationHelper.hasData() prüft einfach, ob die Zeile leer ist. Aus irgendeinem Grund enthalten die Felder manchmal die Datafield-String-Wert statt SortFields, damit die Prüfung, bevor Sie die ‚Felder‘ Eigenschaft:

private function compareEmptyAlwaysLast(a:Object, b:Object, fields:Array = null):int { 
    var result:int; 
    if (!ValidationHelper.hasData(a)) { 
     result = 1; 
    } else if (!ValidationHelper.hasData(b)) { 
     result = -1; 
    } else { 
     if (fields && fields.length > 0 && fields[0] is SortField) { 
      STATIC_SORT.fields = fields; 
     } 
     var f:Function = STATIC_SORT.compareFunction; 
     result = f.call(null,a,b,fields); 
    } 
    return result; 
} 
-1

ich nicht diese Ansätze gefunden, für meine Situation zu arbeiten, was zu alphabetize war eine Liste von Strings und fügen Sie am Ende der Liste ein Element 'Create new ...' hinzu.

Die Art, wie ich die Dinge gehandhabt habe, ist ein wenig unelegant, aber zuverlässig.

ich meine ArrayCollection von Strings sortiert, genannt orgNameList, mit einem Alpha-Art, etwa so:

var alphaSort:Sort = new Sort(); 
    alphaSort.fields = [new SortField(null, true)]; 
    orgNameList.sort = alphaSort; 
    orgNameList.refresh(); 

Dann kopierte ich die Elemente der sortierten Liste in eine neue ArrayCollection, genannt customerDataList. Das Ergebnis ist, dass die neuen ArrayCollection Elemente in alphabetischer Reihenfolge sind, aber nicht unter dem Einfluss eines Sort Objekts stehen. Wenn Sie also ein neues Element hinzufügen, wird es am Ende der ArrayCollection hinzugefügt. Ebenso funktioniert das Hinzufügen eines Elements zu einem bestimmten Index in ArrayCollection auch wie erwartet.

for each(var org:String in orgNameList) 
    { 
     customerDataList.addItem(org); 
    } 

Dann habe ich gerade auf dem 'Create new ...Artikel, wie folgt:

if(userIsAllowedToCreateNewCustomer) 
    { 
     customerDataList.addItem(CREATE_NEW); 
     customerDataList.refresh(); 
    }