web-dev-qa-db-ger.com

Angular 2 OrderBy Pipe

Ich kann diesen Code nicht von angualr1 nach angle2 übersetzen.

ng-repeat="todo in todos | orderBy: 'completed'"

Das habe ich nach der Antwort von Thierry Templier getan:

hTML-Vorlage:

*ngFor="#todo of todos | sort"

komponentendatei:

@Component({
    selector: 'my-app',
    templateUrl: "./app/todo-list.component.html",
    providers: [TodoService],
    pipes: [ TodosSortPipe ]

})

rohrdatei:

import { Pipe } from "angular2/core";
import {Todo} from './todo';

@Pipe({
  name: "sort"
})
export class TodosSortPipe {
  transform(array: Array<Todo>, args: string): Array<Todo> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

Ich bin sicher, dass der Fehler in @Pipe liegt. Ich versuche, ein Array von Todos zu sortieren, sortiert nach der Eigenschaft todo.completed. Zuerst todo.completed = false und dann todo.complete = true.

Ich bin ehrlich gesagt, ich habe die Transformationsmethode und das Weitergeben der Argumente in dieser Methode und in der Sortiermethode nicht sehr gut verstanden.

Wie lautet das Argument args: string? a und b, was sind sie? Wo kommen sie her?

73
user4956851

Siehe https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe für die vollständige Diskussion. Dieses Zitat ist am relevantesten. Grundsätzlich sollte die Filter- und Sortierlogik bei großen Apps, die aggressiv minimiert werden sollten, auf die Komponente selbst übertragen werden.

"Einige von uns möchten vielleicht nicht aggressiv Minimieren. Dies ist unsere Entscheidung. Aber das Produkt Angular sollte nicht verhindern, dass jemand anderes aggressiv abbaut. Daher entschied das Angular-Team, dass alles, was in Angular geliefert wird sicher abbauen.

Das Angular-Team und viele erfahrene Angular-Entwickler sind stark Es wird empfohlen, die Filter- und Sortierlogik in die Komponente .__ zu verschieben. selbst. Die Komponente kann gefilterteHeros oder sortierteHeros .__ verfügbar machen. Eigenschaft und übernehmen Sie die Kontrolle, wann und wie oft die .__ ausgeführt wird. unterstützende Logik. Alle Funktionen, die Sie in eine Pipe gestellt hätten und die über die App geteilt werden, kann in einer Filterung/Sortierung geschrieben werden gewartet und in die Komponente injiziert. "

56
Vitali Kniazeu

Ich habe die Antwort von @Thierry Templier geändert, damit die Pipe benutzerdefinierte Objekte in Winkel 4 sortieren kann:

import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "sort"
})
export class ArraySortPipe  implements PipeTransform {
  transform(array: any, field: string): any[] {
    if (!Array.isArray(array)) {
      return;
    }
    array.sort((a: any, b: any) => {
      if (a[field] < b[field]) {
        return -1;
      } else if (a[field] > b[field]) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

Und um es zu benutzen:

*ngFor="let myObj of myArr | sort:'fieldName'"

Hoffentlich hilft das jemandem.

45
Sal

Sie könnten hierfür eine benutzerdefinierte Pipe implementieren, die die sort-Methode von Arrays nutzt:

import { Pipe } from "angular2/core";

@Pipe({
  name: "sort"
})
export class ArraySortPipe {
  transform(array: Array<string>, args: string): Array<string> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

Und benutzen Sie dann dieses Rohr wie unten beschrieben. Vergessen Sie nicht, Ihre Pipe im pipes-Attribut der Komponente anzugeben:

@Component({
  (...)
  template: `
    <li *ngFor="list | sort"> (...) </li>
  `,
  pipes: [ ArraySortPipe ]
})
(...)

Dies ist ein einfaches Beispiel für Arrays mit String-Werten. Sie können jedoch eine erweiterte Sortierverarbeitung durchführen (basierend auf Objektattributen bei Objektarrays basierend auf Sortierparametern, ...).

Hier ist eine Übersicht dazu: https://plnkr.co/edit/WbzqDDOqN1oAhvqMkQRQ?p=preview .

Ich hoffe, es hilft dir. Thierry

35

Angular wird nicht mit einem OrderBy-Filter geliefert, aber wenn wir uns dazu entscheiden, brauchen wir einen. Es gibt jedoch einige Vorbehalte, die wir im Hinblick auf Geschwindigkeit und Minimierung berücksichtigen müssen. Siehe unten.

Eine einfache Pfeife würde ungefähr so ​​aussehen.

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'sort'
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

Diese Pipe akzeptiert eine Sortierfunktion (fn) und gibt ihr einen Standardwert, der ein Array von Primitiven sinnvoll sortiert. Wir haben die Möglichkeit, diese Sortierfunktion zu überschreiben, wenn wir dies wünschen.

Es akzeptiert keinen Attributnamen als Zeichenfolge, da Attributnamen der Minifizierung unterliegen. Sie ändern sich, wenn wir unseren Code minimieren, aber Minifier sind nicht intelligent genug, um auch den Wert in der Vorlagenzeichenfolge zu verringern.

Primitive sortieren (Zahlen und Strings)

Wir könnten dies verwenden, um ein Array von Zahlen oder Strings mit dem Standardvergleicher zu sortieren:

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{numbers | sort}}
    {{strings | sort}}
  `
})
export class CatComponent
  numbers:Array<number> = [1,7,5,6]
  stringsArray<string> = ['cats', 'hats', 'caveats']
}

Ein Array von Objekten sortieren

Wenn wir ein Array von Objekten sortieren möchten, können wir ihm eine Komparatorfunktion zuweisen.

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{cats | sort:byName}}
  `
})
export class CatComponent
  cats:Array<Cat> = [
    {name: "Missy"},
    {name: "Squoodles"},
    {name: "Madame Pompadomme"}
  ]
  byName(a,b) {
    return a.name > b.name ? 1 : -1
  }
}

Vorsichtsmaßnahmen - reine gegen unreine Pfeifen

Bei Angular 2 handelt es sich um reine und unreine Rohre. 

Eine reine Pipe optimiert die Änderungserkennung anhand der Objektidentität. Dies bedeutet, dass die Pipe nur ausgeführt wird, wenn das Eingabeobjekt die Identität ändert, beispielsweise wenn Sie dem Array ein neues Element hinzufügen. Es wird nicht in Objekte absteigen. Das heißt, wenn wir beispielsweise ein verschachteltes Attribut ändern: this.cats[2].name = "Fluffy", wird die Pipe nicht erneut ausgeführt. Dies hilft Angular, schnell zu sein. Winkelrohre sind standardmäßig rein.

Ein unreines Rohr prüft dagegen die Objektattribute. Dies macht es möglicherweise viel langsamer. Da es nicht garantieren kann, was die Pipe-Funktion tun wird (vielleicht nach Tageszeit unterschiedlich sortiert), wird eine unreine Pipe jedes Mal ausgeführt, wenn ein asynchrones Ereignis auftritt. Dies verlangsamt Ihre App erheblich, wenn das Array groß ist.

Das Rohr oben ist rein. Das heißt, es wird nur ausgeführt, wenn die Objekte im Array unveränderlich sind. Wenn Sie eine Katze wechseln, müssen Sie das gesamte Katzenobjekt durch ein neues ersetzen.

this.cats[2] = {name:"Tomy"}

Wir können das obige zu einem unreinen Rohr ändern, indem Sie das pure-Attribut setzen:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'sort',
  pure: false
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

Diese Pipe wird in Objekte abgesenkt, ist aber langsamer. Mit Vorsicht verwenden.

8
superluminary

Ich habe eine OrderBy-Pipe erstellt, die genau das macht, was Sie brauchen. Es unterstützt auch die Möglichkeit, mehrere Spalten einer Anzahl von Objekten zu sortieren.

<li *ngFor="#todo in todos | orderBy : ['completed']">{{todo.name}} {{todo.completed}}</li>

Mit dieser Pipe können Sie dem Array nach dem Rendern der Seite weitere Elemente hinzufügen. Das Array wird mit den Aktualisierungen dynamisch sortiert.

Ich habe ein schreibe den Prozess hier auf .

Und hier ist eine funktionierende Demo: http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby und https://plnkr.co/edit/DHLVc0?p=info

7
Cory Shaw

Aktualisiertes OrderByPipe: Fehler beim Sortieren von Strings behoben.

erstellen Sie eine OrderByPipe-Klasse:

import { Pipe, PipeTransform } from "@angular/core";
@Pipe( {
name: 'orderBy'
} )
export class OrderByPipe implements PipeTransform {
transform( array: Array<any>, orderField: string, orderType: boolean ): Array<string> {
    array.sort( ( a: any, b: any ) => {
        let ae = a[ orderField ];
        let be = b[ orderField ];
        if ( ae == undefined && be == undefined ) return 0;
        if ( ae == undefined && be != undefined ) return orderType ? 1 : -1;
        if ( ae != undefined && be == undefined ) return orderType ? -1 : 1;
        if ( ae == be ) return 0;
        return orderType ? (ae.toString().toLowerCase() > be.toString().toLowerCase() ? -1 : 1) : (be.toString().toLowerCase() > ae.toString().toLowerCase() ? -1 : 1);
    } );
    return array;
  }
}

in Ihrem Controller: 

@Component({
pipes: [OrderByPipe]
})

oder in deinem

 declarations: [OrderByPipe]

in Ihrer HTML:

<tr *ngFor="let obj of objects | orderBy : ObjFieldName: OrderByType">

ObjFieldName: Objektfeldname, den Sie sortieren möchten.

OrderByType: boolean; wahr: absteigende Reihenfolge; falsch: aufsteigend;

7
GuoJunjun

Dies funktioniert für jedes Feld, das Sie an es übergeben. ( WICHTIG: Es wird nur alphabetisch geordnet. Wenn Sie ein Datum übergeben, wird es als Alphabet und nicht als Datum geordnet.)

/*
 *      Example use
 *      Basic Array of single type: *ngFor="let todo of todoService.todos | orderBy : '-'"
 *      Multidimensional Array Sort on single column: *ngFor="let todo of todoService.todos | orderBy : ['-status']"
 *      Multidimensional Array Sort on multiple columns: *ngFor="let todo of todoService.todos | orderBy : ['status', '-title']"
 */

import {Pipe, PipeTransform} from "@angular/core";

@Pipe({name: "orderBy", pure: false})
export class OrderByPipe implements PipeTransform {

    value: string[] = [];

    static _orderByComparator(a: any, b: any): number {

        if (a === null || typeof a === "undefined") { a = 0; }
        if (b === null || typeof b === "undefined") { b = 0; }

        if (
            (isNaN(parseFloat(a)) ||
            !isFinite(a)) ||
            (isNaN(parseFloat(b)) || !isFinite(b))
        ) {
            // Isn"t a number so lowercase the string to properly compare
            a = a.toString();
            b = b.toString();
            if (a.toLowerCase() < b.toLowerCase()) { return -1; }
            if (a.toLowerCase() > b.toLowerCase()) { return 1; }
        } else {
            // Parse strings as numbers to compare properly
            if (parseFloat(a) < parseFloat(b)) { return -1; }
            if (parseFloat(a) > parseFloat(b)) { return 1; }
        }

        return 0; // equal each other
    }

    public transform(input: any, config = "+"): any {
        if (!input) { return input; }

        // make a copy of the input"s reference
        this.value = [...input];
        let value = this.value;
        if (!Array.isArray(value)) { return value; }

        if (!Array.isArray(config) || (Array.isArray(config) && config.length === 1)) {
            let propertyToCheck: string = !Array.isArray(config) ? config : config[0];
            let desc = propertyToCheck.substr(0, 1) === "-";

            // Basic array
            if (!propertyToCheck || propertyToCheck === "-" || propertyToCheck === "+") {
                return !desc ? value.sort() : value.sort().reverse();
            } else {
                let property: string = propertyToCheck.substr(0, 1) === "+" || propertyToCheck.substr(0, 1) === "-"
                    ? propertyToCheck.substr(1)
                    : propertyToCheck;

                return value.sort(function(a: any, b: any) {
                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    return !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);
                });
            }
        } else {
            // Loop over property of the array in order and sort
            return value.sort(function(a: any, b: any) {
                for (let i = 0; i < config.length; i++) {
                    let desc = config[i].substr(0, 1) === "-";
                    let property = config[i].substr(0, 1) === "+" || config[i].substr(0, 1) === "-"
                        ? config[i].substr(1)
                        : config[i];

                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    let comparison = !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);

                    // Don"t return 0 yet in case of needing to sort by next property
                    if (comparison !== 0) { return comparison; }
                }

                return 0; // equal each other
            });
        }
    }
}
3
CommonSenseCode

Empfehlen Sie lodash mit eckig, dann ist Ihre Pfeife die nächste:

import {Pipe, PipeTransform} from '@angular/core';
import * as _ from 'lodash'
@Pipe({
    name: 'orderBy'
})
export class OrderByPipe implements PipeTransform {

    transform(array: Array<any>, args?: any): any {
        return _.sortBy(array, [args]);
    }

}

und verwenden Sie es wie in HTML

*ngFor = "#todo of todos | orderBy:'completed'"

und vergessen Sie nicht, Pipe zu Ihrem Modul hinzuzufügen

@NgModule({
    ...,
    declarations: [OrderByPipe, ...],
    ...
})

Dies ist ein guter Ersatz für AngularJs orderby -Pipe in angle 4. Einfach und einfach zu bedienen.

Dies ist die github-URL für weitere Informationen https://github.com/VadimDez/ngx-order-pipe

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'orderBy'
})
export class OrderPipe implements PipeTransform {

  transform(value: any | any[], expression?: any, reverse?: boolean): any {
    if (!value) {
      return value;
    }

    const isArray = value instanceof Array;

    if (isArray) {
      return this.sortArray(value, expression, reverse);
    }

    if (typeof value === 'object') {
      return this.transformObject(value, expression, reverse);
    }

    return value;
  }

  /**
   * Sort array
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private sortArray(value: any[], expression?: any, reverse?: boolean): any[] {
    const isDeepLink = expression && expression.indexOf('.') !== -1;

    if (isDeepLink) {
      expression = OrderPipe.parseExpression(expression);
    }

    let array: any[] = value.sort((a: any, b: any): number => {
      if (!expression) {
        return a > b ? 1 : -1;
      }

      if (!isDeepLink) {
        return a[expression] > b[expression] ? 1 : -1;
      }

      return OrderPipe.getValue(a, expression) > OrderPipe.getValue(b, expression) ? 1 : -1;
    });

    if (reverse) {
      return array.reverse();
    }

    return array;
  }


  /**
   * Transform Object
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private transformObject(value: any | any[], expression?: any, reverse?: boolean): any {
    let parsedExpression = OrderPipe.parseExpression(expression);
    let lastPredicate = parsedExpression.pop();
    let oldValue = OrderPipe.getValue(value, parsedExpression);

    if (!(oldValue instanceof Array)) {
      parsedExpression.Push(lastPredicate);
      lastPredicate = null;
      oldValue = OrderPipe.getValue(value, parsedExpression);
    }

    if (!oldValue) {
      return value;
    }

    const newValue = this.transform(oldValue, lastPredicate, reverse);
    OrderPipe.setValue(value, newValue, parsedExpression);
    return value;
  }

  /**
   * Parse expression, split into items
   * @param expression
   * @returns {string[]}
   */
  private static parseExpression(expression: string): string[] {
    expression = expression.replace(/\[(\w+)\]/g, '.$1');
    expression = expression.replace(/^\./, '');
    return expression.split('.');
  }

  /**
   * Get value by expression
   *
   * @param object
   * @param expression
   * @returns {any}
   */
  private static getValue(object: any, expression: string[]) {
    for (let i = 0, n = expression.length; i < n; ++i) {
      const k = expression[i];
      if (!(k in object)) {
        return;
      }
      object = object[k];
    }

    return object;
  }

  /**
   * Set value by expression
   *
   * @param object
   * @param value
   * @param expression
   */
  private static setValue(object: any, value: any, expression: string[]) {
    let i;
    for (i = 0; i < expression.length - 1; i++) {
      object = object[expression[i]];
    }

    object[expression[i]] = value;
  }
}
3
ganesh kalje

Da wir wissen, dass filter und order by aus ANGULAR 2 entfernt werden und wir eigene schreiben müssen, ist hier ein gutes Beispiel zu plunker und ausführlicher Artikel

Es hat sowohl Filter als auch Orderby verwendet, hier ist der Code für Order Pipe

import { Pipe, PipeTransform } from '@angular/core';    
@Pipe({  name: 'orderBy' })
export class OrderrByPipe implements PipeTransform {

  transform(records: Array<any>, args?: any): any {       
    return records.sort(function(a, b){
          if(a[args.property] < b[args.property]){
            return -1 * args.direction;
          }
          else if( a[args.property] > b[args.property]){
            return 1 * args.direction;
          }
          else{
            return 0;
          }
        });
    };
 }
2
Ali Adravi

Fügen Sie in package.json etwas hinzu (Diese Version ist für Angular 2 in Ordnung):

  "ngx-order-pipe": "^1.1.3",

In Ihrem TypeScript-Modul (und importiert Array):

  import { OrderModule } from 'ngx-order-pipe';
1

Sie können dies für Objekte verwenden:

@Pipe({
  name: 'sort',
})
export class SortPipe implements PipeTransform {

  transform(array: any[], field: string): any[] {
    return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);
  }

}
1
Andre Coetzee

Für Angular 5+ Version können wir ngx-order-pipe-Paket verwenden. 

QUELL-TUTORIAL-LINK

Installationspaket

$ npm install ngx-order-pipe --save

Import in Apps Modul

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { OrderModule } from 'ngx-order-pipe';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    OrderModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

überall verwenden

  <ul>
    <li *ngFor="let item of (dummyData | orderBy:'name') ">
      {{item.name}}
    </li>
  </ul>
0
Code Spy

orderby Pipe in Angular JS unterstützt aber Angular (höhere Versionen) wird nicht unterstützt . Bitte finden Sie die erörterten Details, um die Geschwindigkeit der Leistung zu erhöhen.

https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

0

In der aktuellen Version von Angular2 werden OrderBy- und ArraySort-Pipes nicht unterstützt. Sie müssen dazu einige benutzerdefinierte Pipes schreiben/verwenden.

0
Siva