5

According to the answer of @Dmitry Grinko and @sal in Question...What if I need to pass an array

*ngFor="let myObj of myArr | sort:['name','sex','-age']"

myArr in typescript file

myArr = [ { name: 'G', sex: 'F', age: 15 },
          { name: 'B', sex: 'M', age: 25 },
          { name: 'Z', sex: 'F', age: 18 },
          { name: 'A', sex: 'F', age: 12 },
          { name: 'H', sex: 'M', age: 19 } ];
jay rangras
  • 135
  • 1
  • 1
  • 11
  • Please post the `data` that you want to sort. – hrdkisback Nov 21 '19 at 10:05
  • `[ { name: 'G', sex: 'F', age: 15 }, { name: 'B', sex: 'M', age: 25 }, { name: 'Z', sex: 'F', age: 18 }, { name: 'A', sex: 'F', age: 12 }, { name: 'H', sex: 'M', age: 19 } ]` – jay rangras Nov 21 '19 at 10:10

3 Answers3

5

SortPipe

Create a sort.pipe.ts and replace with the following code:

import { Injectable, Pipe, PipeTransform } from '@angular/core';

export type SortOrder = 'asc' | 'desc';

@Injectable()
@Pipe({
  name: 'sort',
})
export class SortPipe implements PipeTransform {
  transform(value: any[], sortOrder: SortOrder | string = 'asc', sortKey?: string): any {
    sortOrder = sortOrder && (sortOrder.toLowerCase() as any);

    if (!value || (sortOrder !== 'asc' && sortOrder !== 'desc')) return value;

    let numberArray = [];
    let stringArray = [];

    if (!sortKey) {
      numberArray = value.filter(item => typeof item === 'number').sort();
      stringArray = value.filter(item => typeof item === 'string').sort();
    } else {
      numberArray = value.filter(item => typeof item[sortKey] === 'number').sort((a, b) => a[sortKey] - b[sortKey]);
      stringArray = value
        .filter(item => typeof item[sortKey] === 'string')
        .sort((a, b) => {
          if (a[sortKey] < b[sortKey]) return -1;
          else if (a[sortKey] > b[sortKey]) return 1;
          else return 0;
        });
    }
     const sorted = [
      ...numberArray,
      ...stringArray,
      ...value.filter(
          item =>
            typeof (sortKey ? item[sortKey] : item) !== 'number' &&
            typeof (sortKey ? item[sortKey] : item) !== 'string',
      ),
     ];
    return sortOrder === 'asc' ? sorted : sorted.reverse();
  }
}

Then, you must add this pipe into declarations of a module. You can add the AppModule like below:

import { SortPipe } from './shared/pipes/sort.pipe';

@NgModule({
  declarations: [/* ... */, SortPipe],
  providers: [/* ... */, SortPipe],
})
export class AppModule { }

How to use?

In HTML:

<div *ngFor="let myObj of myArr | sort:'asc':'name'">{{ myObj | json }}</div>

In Component:

import { Component } from "@angular/core";
import { SortPipe } from "./shared/pipes/sort.pipe";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  myArr = [
    { name: "G", sex: "F", age: 15 },
    { name: "B", sex: "M", age: 25 },
    { name: "Z", sex: "F", age: 18 },
    { name: "A", sex: "F", age: 12 },
    { name: "H", sex: "M", age: 19 }
  ];

  constructor(private sortPipe: SortPipe) {}

  ngOnInit() {
    const myArr = [
      { name: "G", sex: "F", age: 15 },
      { name: "B", sex: "M", age: 25 },
      { name: "Z", sex: "F", age: 18 },
      { name: "A", sex: "F", age: 12 },
      { name: "H", sex: "M", age: 19 }
    ];

    const sortedArr = this.sortPipe.transform(myArr, "desc", "name");

    console.log(sortedArr);
    // Output: [{"name":"Z","sex":"F","age":18}, 
                {"name":"H","sex":"M","age":19}, 
                {"name":"G","sex":"F","age":15}, 
                {"name":"B","sex":"M","age":25}, 
                {"name":"A","sex":"F","age":12}]
  }
}

See the Stackblitz example: https://stackblitz.com/edit/angular-sort-pipe

  • As you mentioned that `
    {{ myObj | json }}
    ` Above statement is also limited with **asc** and **any param** like **name**. What if I need to pass `
    {{ myObj | json }}
    `
    – jay rangras Nov 22 '19 at 09:02
  • Why do you need this? – Mehmet Erim Nov 26 '19 at 07:25
  • I do need this kind of sorting because same list should be sorted according to the 'asc' first, then if alphabetical order is same, then according to the sex, then according to the age – jay rangras Nov 27 '19 at 04:42
  • Hello @MehmetErim i need your help to sort(up and down sort) and also when (-) get default record you have any idea about that? – Bansi29 Feb 03 '21 at 08:21
2

As Angular 8 docs says:

Angular doesn't provide pipes for filtering or sorting lists. Developers familiar with AngularJS know these as filter and orderBy. There are no equivalents in Angular.

This isn't an oversight. Angular doesn't offer such pipes because they perform poorly and prevent aggressive minification. Both filter and orderBy require parameters that reference object properties. Earlier in this page, you learned that such pipes must be impure and that Angular calls impure pipes in almost every change-detection cycle.

However, you can easily sort

const data = [
{ name: 'G', sex: 'F', age: 15 },
{ name: 'B', sex: 'M', age: 25 },
{ name: 'Z', sex: 'F', age: 18 },
{ name: 'A', sex: 'F', age: 12 },
{ name: 'H', sex: 'M', age: 19 }
];


data.sort((a, b) => {
let name_a = a.name;
let name_b = b.name;

let age_a = a.age;
let age_b = b.age;

let sex_a = a.sex;
let sex_b = b.sex;

if (name_a < name_b) return -1;
if (name_a > name_b) return 1;

if (age_a < age_b) return -1;
if (age_a > age_b) return 1;

if (sex_a < sex_b) return -1;
if (sex_a > sex_b) return 1;

return 0;
})

console.log(data);
StepUp
  • 36,391
  • 15
  • 88
  • 148
2

https://www.npmjs.com/package/ngx-pipes

const numbers = [2, 1, 3];
 
const obj = [
  {id: 4, name: 'Dave', amount: 2},
  {id: 2, name: 'Michael', amount: 2},
  {id: 3, name: 'Dan', amount: 1},
  {id: 1, name: 'John', amount: 1}
];
 
const deepObj = [
  {id: 1, name: 'John', amount: 1337, deep: {prop: 4}},
  {id: 2, name: 'Michael', amount: 42, deep: {prop: 2}},
  {id: 3, name: 'Dan', amount: 1, deep: {prop: 1}},
  {id: 4, name: 'Dave', amount: 2, deep: {prop: 3}}
];

<!-- Returns array ordered by value -->
<p>{{ numbers | orderBy }}</p>  <!-- Output: [1, 2, 3] -->
<p>{{ numbers | orderBy: '-' }}</p>  <!-- Output: [3, 2, 1] -->
 
<!-- Returns array ordered by value of property -->
<p>{{ deepObj | orderBy: 'amount' }}</p>  
<!-- Output: [{id: 3, ...}, {id: 4, ...}, {id: 2, ...}, {id: 1, ...}] -->
<p>{{ deepObj | orderBy: '-amount' }}</p>  
<!-- Output: [{id: 1, ...}, {id: 2, ...}, {id: 4, ...}, {id: 3, ...}] -->
 
<!-- Returns array ordered by value of deep property -->
<p>{{ deepObj | orderBy: 'deep.prop' }}</p>  
<!-- Output: [{id: 3, ...}, {id: 2, ...}, {id: 4, ...}, {id: 1, ...}] -->
<p>{{ deepObj | orderBy: '-deep.prop' }}</p>  
<!-- Output: [{id: 1, ...}, {id: 4, ...}, {id: 2, ...}, {id: 3, ...}] -->
 
<!-- Returns array ordered by mutliple properties -->
<p>{{ obj | orderBy: ['amount', 'id'] }}</p>  
<!-- Output: [{id: 1, ...}, {id: 3, ...}, {id: 2, ...}, {id: 4, ...}] -->

Must be like this

*ngFor="let myObj of myArr | orderBy: ['name','sex','-age']"
Rafael Pizao
  • 742
  • 8
  • 21