9

I want to order my result by a property name but the following gives me an error:

*ngFor="let s of rslt| order by:wind_park">

what i get from back-end:

data = [
  { turbine_name: "Baynne ", wind_park: "Bayone" },
  { turbine_name: "Salstiegl ", wind_park: "Salzst" },
  { turbine_name: "Chradurga - SLL2", wind_park: "Chiarga" },
  { turbine_name: "Moilishte ", wind_park: "Mogihte" },
  { turbine_name: "Mogshte ", wind_park: "Mogshte" }
]

How can I order it and what's the best practice? Thank you all in advance.

Kamran Khatti
  • 3,754
  • 1
  • 20
  • 31

6 Answers6

16

You need to create your own OrderBy pipe to satisfy your needs, lodash is a cool library which has bunch of ready made functions which do the trick orderBy.

import { Pipe, PipeTransform } from "@angular/core";
import { orderBy } from 'lodash';

@Pipe({
 name: "orderBy"
})
export class OrderByPipe implements PipeTransform {
 transform(array: any, sortBy: string, order?: string): any[] {
 const sortOrder = order ? order : 'asc'; // setting default ascending order

  return orderBy(array, [sortBy], [sortOrder]);
  }
}

Usage in template

<div *ngFor="let w of data | orderBy: 'wind_park'">{{ w.wind_park}}</div> //default will sort ascending

for descending pass the desc in pipe

<div *ngFor="let w of data | orderBy: 'wind_park': 'desc'">{{ w.wind_park}}</div>

Make sure you declare pipe in your module

@NgModule({
  imports:  [ BrowserModule, FormsModule ],
  declarations: [ OrderByPipe ], // declare pipe here
  bootstrap:    [ AppComponent ]
 })

Working DEMO

Kamran Khatti
  • 3,754
  • 1
  • 20
  • 31
  • i have implemented it but it does not sort ,i get a json file from back end,there is a field wind_park,but it does not sort it –  Aug 13 '20 at 09:09
  • Can you share your back end response so that I can get idea whats the actual response? – Kamran Khatti Aug 13 '20 at 09:12
  • updated my question with what i get from api,hope its helful –  Aug 13 '20 at 09:17
  • thanks a lot it works but i have to add 'asc' also ,this lodash library is common?seems its very useful –  Aug 13 '20 at 09:33
  • yeah its common and pretty much helpful have bunch of stuff out of the box, I have updated my answer and if you notice added `order?: string` ? mark in pipe transform to make order param optional. – Kamran Khatti Aug 13 '20 at 09:35
4

Angular does not provide a pipe for sorting items. You have to implement it yourself. I think the best way to sort items is through a pipe. That is a simple example:

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

@Pipe({
  name: "sort"
})
export class ArraySortPipe  implements PipeTransform {
  transform(array: any, field: string): any[] {
    if (!Array.isArray(array)) {
      return;
    }
    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;
  }
}

To use it:

*ngFor="let value of myArr | sort:'fieldName'
AmD
  • 399
  • 2
  • 12
2

Do it like this:

*ngFor="let s of rslt | order_by:'wind_park'">

Your Pipe:

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

@Pipe({
  name: 'order_by'
})

export class SortPipe implements PipeTransform {
  transform(value: any, propName: string) {

   return value.sort((a, b) => {
      if (a[propName] < b[propName]) {
        return -1;
      } else if (a[propName] === b[propName]) {
        return 0;
      } else if (a[propName] > b[propName]) {
        return 1;
      }
      // if(a[propName] > b[propName]) return 1
      // else return 1;
    });

  }
}

Working example: https://stackblitz.com/edit/angular-ivy-knency?file=src%2Fapp%2Fapp.component.ts

Screenshot of working example:

enter image description here

2

Kamran Khatti answer totally works, but if you decided not to create custom pipe you can use angular build in keyvaluepipe, it accepts custom compare function as a paramter.

component.html

<div *ngFor="let title of data | keyvalue:customsort"> 
  {{title.key}} ----- {{title.value.turbine_name}}
</div>

component.ts

customsort = 
   ((a, b)=>{
     if(a.value[this.propName] === b.value[this.propName]){
       return 0
     }else if(a.value[this.propName] === null){
       return -1;
     }else if(b.value[this.propName] === null){
       return 1;
     }
    return a.value[this.propName].toString().localeCompare(b.value[this.propName].toString());
  });

Working Example

Chellappan வ
  • 23,645
  • 3
  • 29
  • 60
  • why its getting two values? a,b? and whats that-1 and 1?..thanks –  Aug 13 '20 at 14:05
  • It's just custom compareFunction, you can learn more about here:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort – Chellappan வ Aug 13 '20 at 14:10
0

Try one of these

*ngFor="let s of rslt| orderBy:['wind_park']">

Please refer to No filter or orderBy Pipe in Angular discussion Or

Create your own orderBy Pipe like in this answer

If all these doesn't satisfy you, you can install lodash to your project and then create your own pipe as follow

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 _.orderBy(array, ['field1', 'field2'], ['asc', 'desc']);
    }

}

and you can use it like

*ngFor="let s of rslt| orderBy:'wind_park'">

For this to work you need to import this to your module

@NgModule({
    ...,
    declarations: [OrderByPipe, ...],
    ...
})

Hope it helps.

Kirubel
  • 1,461
  • 1
  • 14
  • 33
  • No pipe found with name 'orderBy' –  Aug 13 '20 at 08:23
  • I've added some useful links to my answer. – Kirubel Aug 13 '20 at 08:28
  • I see the no pipe for sort link referenced a lot on stack overflow, but as far as I can tell, it doesn't take to relevant documentation anymore. I think I get why we don't want to do it, but it would be nice if someone had a more up to date reference. I haven't been able to find any actual information on it other than people saying not to do it with an out of date link. – S. Buda Jul 08 '22 at 14:17
0

expanded version with localcompare suggestion:

/*
 *ngFor="let c of oneDimArray | orderBy:'asc'"
 *ngFor="let c of arrayOfObjects | orderBy:'asc':'propertyName'"
*/
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'orderBy',
  pure: true
})
export class OrderByPipe implements PipeTransform {

  private static sortOrderLocale(a: string, b: string, propertyName: string = ''): number {
    const lang = document.documentElement.lang;
    if (propertyName) {
      return a[propertyName].localeCompare(b[propertyName], lang, { ignorePunctuation: true });
    } else {
      return a.localeCompare(b, lang, { ignorePunctuation: true });
    }
  }

  transform(value: any[], order = '', propertyName?: string): any[] {
    if (!value || order === '' || !order) { return value; } // no array or object
    if (propertyName) {
      // object sort
      if (order === 'asc') {
        return value.sort((a: any, b: any) => OrderByPipe.sortOrderLocale(a, b, propertyName));
      }
      else {
        return value.sort((a: any, b: any) => OrderByPipe.sortOrderLocale(b, a, propertyName));
      }
    }
    else {
      // array sort
      if (order === 'asc') {
        return value.sort((a: any, b: any) => OrderByPipe.sortOrderLocale(a, b));
      }
      else {
        return value.sort((a: any, b: any) => OrderByPipe.sortOrderLocale(b, a));
      }
    }
  }
}
Ron Jonk
  • 706
  • 6
  • 16