在Angular2中对对象数组进行排序
Posted
技术标签:
【中文标题】在Angular2中对对象数组进行排序【英文标题】:Sort an array of objects in Angular2 【发布时间】:2017-04-27 11:44:06 【问题描述】:我在 Angular2 中对对象数组进行排序时遇到问题。
对象看起来像:
[
"name": "t10",
"ts": 1476778297100,
"value": "32.339264",
"xid": "DP_049908"
,
"name": "t17",
"ts": 1476778341100,
"value": "true",
"xid": "DP_693259"
,
"name": "t16",
"ts": 1476778341100,
"value": "true",
"xid": "DP_891890"
]
并且被存储在values
变量中。
我只想让*ngFor
循环按name
属性对其进行排序。
<table *ngIf="values.length">
<tr *ngFor="let elem of values">
<td> elem.name </td>
<td> elem.ts </td>
<td> elem.value </td>
</tr>
</table>
尝试使用管道进行此操作,但惨遭失败。 任何帮助表示赞赏。
Plunker 链接:https://plnkr.co/edit/e9laTBnqJKb8VzhHEBmn?p=preview
编辑
我的烟斗:
import Component, Inject, OnInit, Pipe, PipeTransform from '@angular/core';
@Component(
selector: 'watchlist',
templateUrl: './watchlist.component.html',
styleUrls: ['./watchlist.component.css'],
pipes: [ ArraySortPipe ]
)
@Pipe(
name: "sort"
)
export class ArraySortPipe implements PipeTransform
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
名称放入 html 文件:
<tr *ngFor="let elem of values | sort">
【问题讨论】:
到目前为止您尝试了什么?你可以在这里添加你尝试写的管道吗? @toskv 我制作的管道无法正常工作,但我会尽快在编辑中添加它。 谢谢。展示你的工作对人们能够帮助你很重要。 :) 由于您是新手,如果您还没有阅读指南,可能值得一读。 ***.com/help/how-to-ask 也许您应该尝试对 name 属性进行排序。在管道中的箭头函数中 do 和 a.name 【参考方案1】:这适用于任何此类用例。
import Pipe, PipeTransform from '@angular/core';
@Pipe(
name: 'sortBy'
)
export class SortByPipe implements PipeTransform
transform(arr: Array<any>, prop: any, reverse: boolean = false): any
if (arr === undefined) return
const m = reverse ? -1 : 1
return arr.sort((a: any, b: any): number =>
const x = a[prop]
const y = b[prop]
return (x === y) ? 0 : (x < y) ? -1*m : 1*m
)
用法:-<div *ngFor="let item of list | sortBy: 'isDir': true">
更新 请参考Bo's 的回答,因为不建议在管道中进行过滤和排序。
【讨论】:
结帐angular.io/guide/pipes#no-filter-pipe在这里排序不是一个好习惯。 Bo Vandersteene ,更新了我的答案。您可以取消您的反对票。谢谢【参考方案2】:试试这个
从 A 到字母的结尾排序:
this.suppliers.sort((a,b)=>a.SupplierName.localeCompare(b.SupplierName));
Z=>A(倒序)
this.suppliers.sort((a,b)=>b.SupplierName.localeCompare(a.SupplierName));
【讨论】:
最简单的有效答案,不值得反对。 不反对投票,但对代码的一些解释会有所帮助。A=>Z
这是箭头函数的简写吗?也许澄清一下“localeCompare”是一种包含特定语言字符的内置方法?
当放置在订阅所在的构造函数中时,这对我有用: this.foo.getBar().subscribe(x => this.thing = x; this.thing= (this.thing || []).sort((a: Thing, b: Thing) => a.name.localeCompare(b.name)); );我看到 a=>z 是文本。在那里完全困惑了一段时间:)
@RinandLen 'localeCompare' 根据顺序返回负值、正值或零值。然后 sort 函数使用它对其进行排序。 developer.mozilla.org/en-US/docs/Web/javascript/Reference/…developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案3】:
很简单,例如如果你有这个数组对象:
cars = ["Dodge", "Fiat", "Audi", "Volvo", "BMW", "Ford"];
如果您想让对象在 HTML 前面排序,请使用:
<li ng-repeat="x in cars | orderBy">x</li>
默认情况下,字符串按字母排序,数字按数字排序。
如果你有这个带键的数组:
customers = [
"name" : "Bottom-Dollar Marketse" ,"city" : "Tsawassen",
"name" : "Alfreds Futterkiste", "city" : "Berlin",
"name" : "Bon app", "city" : "Marseille",
"name" : "Cactus Comidas para llevar", "city" : "Buenos Aires",
"name" : "Bolido Comidas preparadas", "city" : "Madrid",
"name" : "Around the Horn", "city" : "London",
"name" : "B's Beverages", "city" : "London"
];
用途:
按“城市”DESC 顺序对数组进行排序:
<li ng-repeat="x in customers | orderBy : '-city'">x.name + ", " + x.city</li>
按“城市”对数组进行排序:
<li ng-repeat="x in customers | orderBy : 'city'">x.name + ", " + x.city</li>
【讨论】:
显然 ng-repeat 适用于旧版本的 angularJs,最近使用 * ngFor 在 Angular 1.x 或 Angular 2+ 中仍然不是一个好习惯【参考方案4】:Angular 仍然建议不要像在 angularJs 中那样使用管道进行排序和过滤。
它会减慢您的应用程序,出现一些性能问题。在将组件传递给模板之前,最好在组件中提供排序。
原因在https://angular.io/guide/pipes#no-filter-pipe有解释
如果你使用一个漂亮的结构化组件布局,你甚至可以在 te setter 上做到这一点:
@Input()
set users(users: Array<User>)
this.usersResult = (users || []).sort((a: User, b: User) => a.name < b.name ? -1 : 1)
【讨论】:
什么是“userResult”(除了你编的一个变量)?它在上面的代码中显然是未定义的,没有在其他地方声明,并且将其更改为我的组件中的任何现有值都会产生“超出最大调用堆栈大小”。 用户结果将是您的排序数组的结果。您只需将其重新分配给其他东西【参考方案5】:您的管道需要字符串,但它获取对象,您应该调整它:
export class ArraySortPipe implements PipeTransform
transform(array: Array<any>): Array<string>
array.sort((a: any, b: any) =>
if (a.name < b.name)
return -1;
else if (a.name > b.name)
return 1;
else
return 0;
);
return array;
【讨论】:
不幸的是它不起作用。将您的解决方案包含到我的项目中后,我收到一个错误:Argument of type ' selector: string; template: any; styles: any[]; pipes: typeof ArraySortPipe[]; ' is not assignable to parameter of type 'Component'. Object literal may only specify known properties, and 'pipes' does not exist in type 'Component'.
可能是签名的原因,更新为接受Array,试试看
这里几乎是整个component.ts
文件和出现的错误:jsfiddle.net/ra7szrLn/1 即使我已经改变了你所说的一切,它仍然有问题。
该错误是由于 jsfiddle 上的编译问题还是我错过了什么?为什么不分叉并修复原来的 plnkr?
这个错误来自 webpack 在编译应用程序时。我现在使用了 jsfiddle,因为我在 plunker 上发布了我的代码的最小且非常简化的版本,没有 http 请求。如果你愿意,我可以编辑原来的 plunker,我的朋友。【参考方案6】:
虽然您可以使用管道解决此问题,但您必须问问自己,管道的可重用性是否对您在特定项目中有用。以后是否经常需要在其他数组或其他组件上按“name”键对对象进行排序?这些数据是否会经常发生变化,并且以难以在组件中简单排序的方式发生变化?您是否需要根据视图或输入的任何更改对数组进行排序?
我创建了一个已编辑的 plunker,其中数组在组件的构造函数中排序,但没有理由不能将此功能移出到它自己的方法(例如 sortValuesArray)中以便在必要时重新使用。
constructor()
this.values.sort((a, b) =>
if (a.name < b.name) return -1;
else if (a.name > b.name) return 1;
else return 0;
);
Edited Plunker
【讨论】:
谢谢,但这不是我要找的。span> 在某些情况下,代码可能更简单,如constructor() this.values.sort(function(a, b)return a.ts - b.ts);
或constructor() this.values.sort((a, b) => return a.ts - b.ts);
这种方法的论据在angular.io/guide/pipes 提出:“Angular 不提供这样的管道,因为它们性能很差......过滤,尤其是排序是昂贵的操作。用户体验可能会严重降低当 Angular 每秒多次调用这些管道方法时,即使是中等大小的列表。filter 和 orderBy 在 AngularJS 应用程序中经常被滥用,导致抱怨 Angular 本身很慢...... Angular 团队和许多有经验的 Angular 开发人员强烈建议移动过滤并将逻辑排序到组件本身。”以上是关于在Angular2中对对象数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章