Sort an array of objects in Angular2
Solution 1
Although you can solve this problem with a pipe, you have to ask yourself if the re-usability of a pipe is useful to you in your particular project. Will you often need to sort objects by the "name" key on other arrays or other components in the future? Will this data be changing often enough and in ways that make it hard to simply sort in the component? Will you need the array sorted on any change to the view or inputs?
I created an edited plunker in which the array is sorted in the component's constructor, but there's no reason this functionality couldn't be moved out into its own method (sortValuesArray for instance) for re-use if necessary.
constructor() {
this.values.sort((a, b) => {
if (a.name < b.name) return -1;
else if (a.name > b.name) return 1;
else return 0;
});
}
Solution 2
Try this
Sort from A to end of alpahbet:
this.suppliers.sort((a,b)=>a.SupplierName.localeCompare(b.SupplierName));
Z=>A (reverse order)
this.suppliers.sort((a,b)=>b.SupplierName.localeCompare(a.SupplierName));
Solution 3
Your pipe expects strings but it gets objects, you should adapt it:
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;
}
}
Solution 4
Angular still advice not to use pipes for sorting and filtering, like in angularJs.
It will slow down your application, have some performance issues. It is a lot better to provide your sorting in your component before passing it to the template.
The reason is explained on https://angular.io/guide/pipes#no-filter-pipe
If you work with a nice structured component layout you can do it even on te setter:
@Input()
set users(users: Array<User>) {
this.usersResult = (users || []).sort((a: User, b: User) => a.name < b.name ? -1 : 1)
}
Solution 5
This is adaptable to any such usecase.
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
})
}
}
Usage:-
<div *ngFor="let item of list | sortBy: 'isDir': true">
UPDATE
Refer Bo's answer as filtering and sorting in pipes is not recommended.
Related videos on Youtube
![Admin](/assets/logo_square_200-5d0d61d6853298bd2a4fe063103715b4daf2819fc21225efa21dfb93e61952ea.png)
Admin
Updated on July 09, 2022Comments
-
Admin almost 2 years
I have problems with sorting an array of object in Angular2.
The object looks like:
[ { "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" } ]
And is being stored inside the
values
variable.All I want is to make the
*ngFor
loop sort it by thename
property.<table *ngIf="values.length"> <tr *ngFor="let elem of values"> <td>{{ elem.name }}</td> <td>{{ elem.ts }}</td> <td>{{ elem.value }}</td> </tr> </table>
Tried to do it with pipes, but failed miserably. Any help appreciated.
Plunker link: https://plnkr.co/edit/e9laTBnqJKb8VzhHEBmn?p=preview
Edit
My pipe:
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; } }
And just put the
pipe
name into html file:<tr *ngFor="let elem of values | sort">
-
toskv over 7 yearswhat did you try so far? Can you add the pipe you tried to write here?
-
Admin over 7 years@toskv The pipe which Ive made doesnt work properly but I will add it asap in the edit.
-
toskv over 7 yearsthanks. showing your work in important for people to be able to help you. :)
-
toskv over 7 yearsSince you are new it might be worth to read the how to ask a guide, if you haven't already. stackoverflow.com/help/how-to-ask
-
toskv over 7 yearsmaybe you should try sorting on the name property. in the arrow function in the pipe do and a.name < b.name. :)
-
-
Admin over 7 yearsUnfortunately it doesn't work. After including your solution into my project, I'm receiving an error:
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'.
-
Meir over 7 yearsIt is probably because of the signature, updated it to accept Array<any>, give it a try.
-
Admin over 7 yearsThank you but it's not exactly what Im looking for.
-
Admin over 7 yearsHere's almost the whole
component.ts
file and the error which appears: jsfiddle.net/ra7szrLn/1 It's still something wrong, even if I've changed everything what you said. -
Meir over 7 yearsThe error is due to compilation issue on jsfiddle or am I missing someting? Why not fork and fix the original plnkr?
-
Admin over 7 yearsThis error is from webpack while compiling the app. I've used jsfiddle now because on the plunker Ive posted minimal and very simplified version of my code, without http requests. I can edit the original plunker if you wish, my friend.
-
Meir over 7 yearsWhat version on angular are you using? Is it with angular-cli? The pipes keyword was removed in the final release and you should import the pipe in the module instead
-
Admin over 7 yearsYes, I'm using the angular-cli. Version: webpack 2.1.0-beta.25. I didn't know about the obligatory to use it in the module. Thank you for that.
-
Meir over 7 yearsBest way is the you use 'ng g pipe my-pipe' and see how angular adds it and if it creates a module
-
Admin over 7 yearsAngular-cli created only two files, one for tests and another is a component, with following code:
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'sortBy' }) export class SortByPipe implements PipeTransform { transform(value: any, args?: any): any { return null; } }
-
Meir over 7 yearsTry putting the logic inside this one
-
Admin over 7 yearsUh, hold on, it has also added this code into the
app.module
:import { SortByPipe } from './sort-by.pipe';
-
Meir over 7 yearsThat's what I said. No pipes field, just import in the module
-
Admin over 7 yearsBut I dont fully understand, you mean that I have to delete the
@Pipe
and thepipe class
from the component, and just use that file created by angular? -
Mickey Segal almost 7 yearsIn some circumstances the code could be even simpler as
constructor() { this.values.sort(function(a, b){return a.ts - b.ts}); }
-
Mickey Segal almost 7 yearsAs discussed at angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe using the pipe approach is discouraged because "The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second... The Angular team and many experienced Angular developers strongly recommend moving filtering and sorting logic into the component itself." This approach was used in the answer by @Peter.
-
Mickey Segal almost 7 yearsOr
constructor() { this.values.sort((a, b) => {return a.ts - b.ts}); }
-
Mickey Segal almost 7 yearsThe argument for this approach is made at angular.io/guide/pipes: "Angular doesn't offer such pipes because they perform poorly ... Filtering and especially sorting are expensive operations. The user experience can degrade severely for even moderate-sized lists when Angular calls these pipe methods many times per second. filter and orderBy have often been abused in AngularJS apps, leading to complaints that Angular itself is slow... The Angular team and many experienced Angular developers strongly recommend moving filtering and sorting logic into the component itself."
-
Wanjia over 6 yearsSimplest answer that works, doesn't deserve downvotes.
-
Andres Pirona almost 6 yearsObviously ng-repeat is for old versions of angularJs, for recent uses * ngFor
-
Rin and Len almost 6 yearsNot down-voting but some explanation of the code would help.
A=>Z
is this shorthand for an arrow function? Maybe clarify that "localeCompare" is a built-in method for including language-specific characters? -
Rin and Len almost 6 yearsWhat is "userResult" (aside from a var you made up)? It's undefined obviously in the code above, not being declared elsewhere, and changing it to any existing value in my component yields "max call stack size exceeded".
-
Rin and Len almost 6 yearsThis worked for me when placed inside the constructor where the subscribe is: this.foo.getBar().subscribe(x => { this.thing = x; this.thing= (this.thing || []).sort((a: Thing, b: Thing) => a.name.localeCompare(b.name)); }); I see that the a=>z thing was text. Totally confused for a while there :)
-
Bo Vandersteene over 5 yearsUser result will be the result of your sorted array. You just reassign it to something else
-
Bo Vandersteene over 5 yearsCheckout angular.io/guide/pipes#no-filter-pipe it is not a good practice to sort here.
-
Bo Vandersteene over 5 yearsIt is still not a good practice, neither in angular 1.x or Angular 2+
-
Vikas Gautam over 5 yearsBo Vandersteene , Updated my answer. You can cancel your down vote. thanks
-
Devaarth over 3 years@RinandLen 'localeCompare' returns negative, positive or zero value based on order. Then sort function uses that to sort it. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…