Angular 2 OrderBy Pipe

No puedo traducir este código de angualr1 a angular2, ¿hay alguna ayuda?

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

Esto es lo que hice después de la respuesta de Thierry Templier:

plantilla html:

 *ngFor="#todo of todos | sort" 

archivo componente:

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

archivo de tubería

 import { Pipe } from "angular2/core"; import {Todo} from './todo'; @Pipe({ name: "sort" }) export class TodosSortPipe { transform(array: Array, args: string): Array { array.sort((a: any, b: any) => { if (a  b) { return 1; } else { return 0; } }); return array; } } 

Estoy seguro de que el error está en @Pipe, estoy tratando de ordenar una matriz de Todos, ordenada por la propiedad todo.completed. Primero todo.completed = falso y el todo.complete = verdadero.

Soy honesto, no entendí muy bien el método de transformación y cómo pasar los argumentos en ese método y en el método de clasificación.

Me gusta, ¿cuál es el argumento args: string? ayb, ¿qué son? ¿De dónde vienen?

Por favor, consulte https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe para la discusión completa. Esta cita es muy relevante. Básicamente, para las aplicaciones a gran escala que deben ser miniaturizadas de manera agresiva, la lógica de filtrado y clasificación debe pasar al componente en sí.

“Es posible que a algunos de nosotros no nos importe ministrar de forma agresiva. Esa es nuestra elección. Pero el producto Angular no debería evitar que otra persona ministre agresivamente. Por lo tanto, el equipo de Angular decidió que todo lo enviado en Angular se miniaturizaría de forma segura.

El equipo de Angular y muchos desarrolladores angulares con experiencia recomiendan encarecidamente que mueva la lógica de filtrado y clasificación al componente mismo. El componente puede exponer una propiedad filteredHeroes o sortedHeroes y tomar el control sobre cuándo y con qué frecuencia ejecutar la lógica de soporte. Cualquier capacidad que haya puesto en una tubería y compartida en la aplicación se puede escribir en un servicio de filtrado / clasificación e inyectar en el componente “.

Podría implementar una tubería personalizada para esto que aproveche el método de sort de matrices:

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

Y use esta tubería como se describe a continuación. No olvide especificar su tubería en el atributo pipes del componente:

 @Component({ (...) template: ` 
  • (...)
  • `, pipes: [ ArraySortPipe ] }) (...)

    Es una muestra simple para matrices con valores de cadena pero puede tener algún procesamiento de clasificación avanzado (basado en atributos de objeto en el caso de la matriz de objetos, basada en parámetros de clasificación, …).

    Aquí hay un plunkr para esto: https://plnkr.co/edit/WbzqDDOqN1oAhvqMkQRQ?p=preview .

    Espero que te ayude, Thierry

    Modifiqué la respuesta de @Thierry Templier para que la tubería pueda ordenar objetos personalizados en el ángulo 4:

     import { Pipe, PipeTransform } from "@angular/core"; @Pipe({ name: "sort" }) export class ArraySortPipe implements PipeTransform { transform(array: any[], field: string): any[] { 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; } } 

    Y para usarlo:

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

    Espero que esto ayude a alguien.

    Creé un tubo OrderBy que hace justo lo que necesita. Es compatible con la posibilidad de ordenar en varias columnas de un enumerable de objetos también.

     
  • {{todo.name}} {{todo.completed}}
  • Esta tubería permite agregar más elementos a la matriz después de representar la página, y ordena la matriz con las actualizaciones de forma dinámica.

    Tengo un escrito sobre el proceso aquí .

    Y aquí hay una demostración en funcionamiento: http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby y https://plnkr.co/edit/DHLVc0?p=info

    OrderByPipe actualizado: arreglado no ordenando cadenas.

    crea una clase OrderByPipe:

     import { Pipe, PipeTransform } from "@angular/core"; @Pipe( { name: 'orderBy' } ) export class OrderByPipe implements PipeTransform { transform( array: Array, orderField: string, orderType: boolean ): Array { 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; } } 

    en tu controlador:

     @Component({ pipes: [OrderByPipe] }) 

    o en tu

      declarations: [OrderByPipe] 

    en tu html:

      

    ObjFieldName: nombre del campo de objeto que desea ordenar;

    OrderByType: boolean; verdadero: orden descendente; falso: ascendente;

    Angular no viene con una orden Por filtro de fábrica, pero si decidimos que necesitamos uno, podemos hacer uno fácilmente. Sin embargo, hay algunas advertencias que debemos tener en cuenta para hacer con la velocidad y la minificación. Vea abajo.

    Una tubería simple se vería algo como esto.

     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) } } 

    Esta tubería acepta una función de clasificación ( fn ) y le da un valor predeterminado que ordenará una matriz de primitivas de una manera sensata. Tenemos la opción de anular esta función de clasificación si lo deseamos.

    No acepta un nombre de atributo como una cadena, porque los nombres de los atributos están sujetos a la minificación. Cambiaran cuando minimicemos nuestro código, pero los minificadores no son lo suficientemente inteligentes como para minificar el valor en la cadena de la plantilla.

    Primitivas de ordenación (números y cadenas)

    Podríamos usar esto para ordenar una matriz de números o cadenas usando el comparador predeterminado:

     import { Component } from '@angular/core'; @Component({ selector: 'cat', template: ` {{numbers | sort}} {{strings | sort}} ` }) export class CatComponent numbers:Array = [1,7,5,6] stringsArray = ['cats', 'hats', 'caveats'] } 

    Ordenar una matriz de objetos

    Si queremos ordenar una matriz de objetos, podemos darle una función de comparación.

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

    Advertencias: tuberías puras versus impuras

    Angular 2 tiene un concepto de tuberías puras e impuras.

    Un tubo puro optimiza la detección de cambios utilizando la identidad del objeto. Esto significa que la tubería solo se ejecutará si el objeto de entrada cambia de identidad, por ejemplo, si agregamos un nuevo elemento a la matriz. No descenderá a los objetos. Esto significa que si cambiamos un atributo nested: this.cats[2].name = "Fluffy" por ejemplo, la tubería no se volverá a ejecutar. Esto ayuda a Angular a ser rápido. Los tubos angulares son puros por defecto.

    Un tubo impuro por otro lado verificará los atributos del objeto. Esto potencialmente lo hace mucho más lento. Debido a que no puede garantizar lo que hará la función de tubería (tal vez ordenada de manera diferente según la hora del día, por ejemplo), se ejecutará una tubería impura cada vez que ocurra un evento asincrónico. Esto ralentizará considerablemente tu aplicación si la matriz es grande.

    El tubo de arriba es puro. Esto significa que solo se ejecutará cuando los objetos en la matriz sean inmutables. Si cambia un gato, debe reemplazar el objeto cat completo por uno nuevo.

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

    Podemos cambiar lo anterior a una tubería impura estableciendo el atributo puro:

     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) } } 

    Esta tubería descenderá a los objetos, pero será más lenta. Usar con precaución.

    Esto funcionará para cualquier campo que pases a él. ( IMPORTANTE: solo ordenará alfabéticamente, de modo que si pasa una fecha, lo ordenará como alfabeto, no como fecha)

     /* * 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"ta 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 }); } } } 

    Este es un buen reemplazo para el tubo de pedido AngularJs en angular 4 . Fácil y simple de usar

    Esta es la URL de github para obtener más información 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; } } 

    Recomiéndele usar lodash con angular, luego su pipa será la siguiente:

     import {Pipe, PipeTransform} from '@angular/core'; import * as _ from 'lodash' @Pipe({ name: 'orderBy' }) export class OrderByPipe implements PipeTransform { transform(array: Array, args?: any): any { return _.sortBy(array, [args]); } } 

    y usarlo en html como

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

    y no olvide agregar Pipe a su módulo

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

    Como sabemos que el filtro y el orden por se eliminan de ANGULAR 2 y tenemos que escribir el nuestro, aquí hay un buen ejemplo de plunker y artículo detallado

    Usó filtro y orderby, aquí está el código para order pipe

     import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'orderBy' }) export class OrderrByPipe implements PipeTransform { transform(records: Array, 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; } }); }; } 

    Puedes usar esto para objetos:

     @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); } } 

    En la versión actual de Angular2, las canalizaciones orderBy y ArraySort no son compatibles. Necesita escribir / usar algunos tubos personalizados para esto.