Angular 2 OrderBypipe道
我无法将这个代码从angualr1翻译成angular2,有什么帮助?
ng-repeat="todo in todos | orderBy: 'completed'"
这就是我在Thierry Templier的回答之后所做的:
html模板:
*ngFor="#todo of todos | sort"
组件文件:
@Component({ selector: 'my-app', templateUrl: "./app/todo-list.component.html", providers: [TodoService], pipes: [ TodosSortPipe ] })
pipe道文件:
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; } }
我敢肯定,错误是在@Pipe,即时通讯尝试sorting的Todos数组,由物业todo.completed命令。 首先todo.completed = false并且比todo.complete = true。
我很诚实,我不太了解转换方法,以及如何在该方法和sorting方法中传递参数。
比如,args:string参数是什么? a和b,他们是什么? 他们从哪里来?
有关完整的讨论,请参阅https://angular.io/docs/ts/latest/guide/pipes.html#!#no-filter-pipe 。 这个引用是最相关的。 基本上,对于大规模应用程序,应该积极缩小过滤和sorting逻辑应该移动到组件本身。
“我们有些人可能并不在意这样做,这是我们的select,但是Angular产品不应该阻止其他人积极进行缩小,因此,Angular团队决定在Angular中发布的所有东西都会安全地缩小。
Angular团队和许多经验丰富的Angular开发人员强烈build议您将筛选和sorting逻辑移入组件本身。 该组件可以公开一个filteredHeroes或sortedHeroes属性,并控制执行支持逻辑的时间和频率。 你可以在pipe道中放置任何function,并在应用程序中共享,这些function可以写入一个过滤/sorting服务并注入组件。
你可以实现一个自定义pipe道,利用数组的sort
方法:
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; } }
然后使用这个pipe道,如下所述。 不要忘记将pipe道指定到组件的pipes
属性中:
@Component({ (...) template: ` <li *ngFor="list | sort"> (...) </li> `, pipes: [ ArraySortPipe ] }) (...)
这是一个带有string值的数组的简单示例,但您可以进行一些高级sorting处理(基于对象数组的对象属性,基于sorting参数,…)。
这是一个PLUNK: https ://plnkr.co/edit/WbzqDDOqN1oAhvqMkQRQ?p = preview。
希望它能帮助你,Thierry
我修改了@Thierry Templier的响应,以便pipe道可以按照angular4sorting自定义对象:
import { Pipe } from "@angular/core"; @Pipe({ name: "sort" }) export class ArraySortPipe { 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; } }
并使用它:
*ngFor="let myObj of myArr | sort:'fieldName'"
希望这有助于某人。
我已经创build了一个OrderBypipe道,只是你需要的。 它支持能够在一个枚举对象的多个列上进行sorting。
<li *ngFor="#todo in todos | orderBy : ['completed']">{{todo.name}} {{todo.completed}}</li>
这个pipe道允许在渲染页面之后向数组添加更多的项目,并且dynamic地对数组进行sorting。
我在这里写下这个过程 。
这里有一个工作演示: http : //fuelinteractive.github.io/fuel-ui/#/pipe/orderby和https://plnkr.co/edit/DHLVc0?p=info
Angular没有提供一个orderByfilter,但是如果我们决定需要一个,我们可以轻松地创build一个。 但是有一些警告我们需要注意速度和缩小。 见下文。
一个简单的pipe道看起来像这样。
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) } }
这个pipe道接受一个sorting函数( fn
),并给它一个默认值,以合理的方式sorting一个基元数组。 如果我们愿意,我们可以select重写这种sortingfunction。
它不接受属性名称作为string,因为属性名称会被缩小。 当我们缩小代码时,它们会改变,但是缩小器不够聪明,也不能缩小模板string中的值。
排列基元(数字和string)
我们可以使用这个来使用默认的比较器对数组或数组进行sorting:
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'] }
sorting对象数组
如果我们想sorting一个对象数组,我们可以给它一个比较函数。
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 } }
注意事项 – 纯粹与不纯的pipe道
Angular 2有一个纯粹而不纯的pipe道的概念。
纯pipe道使用对象标识来优化更改检测。 这意味着只有当input对象改变了标识时,pipe道才会运行,例如,如果我们向数组添加新的项目。 它不会落入对象。 这意味着如果我们改变一个嵌套的属性: this.cats[2].name = "Fluffy"
,pipe道将不会重新运行。 这有助于Angular快速。 angularpipe是默认的纯粹的。
另一方面, 不纯的pipe道将检查对象属性。 这可能会使速度变慢。 因为它不能保证pipe道function将做什么(可能是根据一天的时间不同来sorting), 每当发生asynchronous事件时,都会运行不纯的pipe道。 如果数组很大,这会使您的应用程序变慢。
上面的pipe道是纯净的。 这意味着只有当数组中的对象是不可变的时候才会运行。 如果你改变一只猫,你必须用一个新的猫replace整个猫对象。
this.cats[2] = {name:"Tomy"}
我们可以通过设置纯属性来将上面的内容更改为不纯的pipe道:
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) } }
这条pipe道将下降到对象,但会更慢。 谨慎使用。
更新OrderByPipe:固定不sorting的string。
创build一个OrderByPipe类:
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; } }
在你的控制器中:
@Component({ pipes: [OrderByPipe] })
或在你的
declarations: [OrderByPipe]
在你的html:
<tr *ngFor="let obj of objects | orderBy : ObjFieldName: OrderByType">
ObjFieldName:要sorting的对象字段名称;
OrderByType:boolean; 真:降序; 假:升序;
这将适用于您传递给它的任何字段。 ( 重要说明:它只会按字母顺序排列,所以如果你通过一个date,它会按照字母sorting而不是date)
/* * 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 }); } } }
build议你使用angular度lodash,然后你的pipe道将是下一个:
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]); } }
并在html中使用它
*ngFor = "#todo of todos | orderBy:'completed'"
不要忘记添加pipe道到你的模块
@NgModule({ ..., declarations: [OrderByPipe, ...], ... })
在当前版本的Angular2中,不支持orderBy和ArraySortpipe道。 您需要为此写入/使用一些自定义pipe道。
由于我们知道filter和命令是从angular度2中删除,我们需要写我们自己的,这里是一个很好的例子,在plunker和详细的文章
它同时使用filter和orderby,这里是订单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; } }); }; }
这可以很好的替代AngularJs的order by pipe 4 。 简单易用。
这是github URL的更多信息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; } }