简体   繁体   中英

Sort an array of objects in Angular2

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 the name 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">

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

Edited Plunker

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

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

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

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.

its simple, for example if you have this array object:

 cars = ["Dodge", "Fiat", "Audi", "Volvo", "BMW", "Ford"];

and you want to have the object sorted in the HTML front, use:

 <li ng-repeat="x in cars | orderBy">{{x}}</li>

By default, strings are sorted alphabetically, and numbers are sorted numerically.

If you have this array with keys:

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"}
];

Use:

Sort the array by "city" DESC order:

<li ng-repeat="x in customers | orderBy : '-city'">{{x.name + ", " + x.city}}</li>

Sort the array by "city":

<li ng-repeat="x in customers | orderBy : 'city'">{{x.name + ", " + x.city}}</li>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM