108

I'm not able to translate this code from Angualr 1 to Angular 2:

ng-repeat="todo in todos | orderBy: 'completed'"

This is what i've done following the Thierry Templier's answer:

Component template:

*ngFor="#todo of todos | sort"

Component code:

@Component({
    selector: 'my-app',
    templateUrl: "./app/todo-list.component.html",
    providers: [TodoService],
    pipes: [ TodosSortPipe ]

})

Pipe code:

import { Pipe } from "angular2/core";
import {Todo} from './todo';

@Pipe({
  name: "sort"
})
export class TodosSortPipe {
  transform(array: Array<Todo>, args: string): Array<Todo> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {
        return 0;
      }
    });
    return array;
  }
}

I'm trying to sort an array of Todos, ordered by the property completed. First todo.completed = false and then the todo.complete = true.

I don't understand very well the transform method and how to pass the arguments in that method and in the sort method.

What is the args: string argument? What are a and b and where they come from?

Alexander Abakumov
  • 13,617
  • 16
  • 88
  • 129

19 Answers19

98

I modified @Thierry Templier's response so the pipe can sort custom objects in angular 4:

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

And to use it:

*ngFor="let myObj of myArr | sort:'fieldName'"

Hopefully this helps someone.

Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86
Sal
  • 5,129
  • 5
  • 27
  • 53
  • 1
    I've got the message: `The pipe 'sort' could not be found`. Can I somehow inject pipe in my component like in angular 2 pipes : [ArraySortPipe]? – Matija Župančić Sep 27 '17 at 11:27
  • See @Thierry Templier response on how to inject the pipe into your app component – Sal Sep 27 '17 at 11:29
  • You need to include "ArraySortPipe" in your modules hierarchy declarations. Something like: import { ArraySortPipe } from './../../shared/filters.pipe'; In 'app.module.ts' and any module under it. put: declarations: [ArraySortPipe] – Dudi Oct 22 '18 at 10:12
  • 1
    Be careful with this implementation as .sort changes the source array, this could cause issues in other parts of your code.. – Peter Oct 19 '22 at 07:20
76

Please see https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe for the full discussion. This quote is most relevant. Basically, for large scale apps that should be minified aggressively the filtering and sorting logic should move to the component itself.

"Some of us may not care to minify this aggressively. That's our choice. But the Angular product should not prevent someone else from minifying aggressively. Therefore, the Angular team decided that everything shipped in Angular will minify safely.

The Angular team and many experienced Angular developers strongly recommend that you move filtering and sorting logic into the component itself. The component can expose a filteredHeroes or sortedHeroes property and take control over when and how often to execute the supporting logic. Any capabilities that you would have put in a pipe and shared across the app can be written in a filtering/sorting service and injected into the component."

v.karbovnichy
  • 3,183
  • 2
  • 36
  • 47
Vitali Kniazeu
  • 1,077
  • 9
  • 10
  • 8
    How should you move the logic "into the component itself" in a way that can "take control over when and how often to execute the supporting logic"? Are there good examples of this to follow? – Mzzzzzz Jan 18 '17 at 17:23
  • 1
    @Mzzzzzz Where it's mentioning a property like `filteredHeroes` and `sortedHeroes`, I think the idea is that while initializing the component you'd run some sorting/filtering logic (maybe calling a method from ngOnInit), then setting that property with the sorted/filtered results, and only re-run logic / update the property if there's something that triggers a need (e.g. user interaction triggers AJAX call to get more heroes, or the user clicks a checkbox to filter half of them away based on some criteria, etc.) – jmq Mar 06 '18 at 15:51
  • So should I use it in the component or use the above solution (custom pipe)? – Ron Rofe Sep 23 '20 at 05:56
  • 2
    FYI: That link target is gone. – tommueller Oct 26 '20 at 14:57
  • Its so annoying to me that pipes even exist. Write code in the controller. Bind to properties in the View. Sure, sometimes its boilerplate - but are we writing _enterprise_ apps or what, here, people!? – Ian Grainger Dec 16 '20 at 12:07
44

You could implement a custom pipe for this that leverages the sort method of arrays:

import { Pipe } from "angular2/core";

@Pipe({
  name: "sort"
})
export class ArraySortPipe {
  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 use then this pipe as described below. Don't forget to specify your pipe into the pipes attribute of the component:

@Component({
  (...)
  template: `
    <li *ngFor="list | sort"> (...) </li>
  `,
  pipes: [ ArraySortPipe ]
})
(...)

It's a simple sample for arrays with string values but you can have some advanced sorting processing (based on object attributes in the case of object array, based on sorting parameters, ...).

Here is a plunkr for this: https://plnkr.co/edit/WbzqDDOqN1oAhvqMkQRQ?p=preview.

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • 1
    Thank you for you answer, can you explain the sort method? –  Feb 02 '16 at 16:42
  • 1
    In fact the `sort` method is a method of the JavaScript `Array` object. See this link: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort. – Thierry Templier Feb 02 '16 at 16:44
  • Ok i got it, it uses the javascript sort method with a compare function as argument. thank you! –  Feb 02 '16 at 16:45
  • Last question, how would you call this file? pipe-comoponent.ts or sort-pipe.ts or something else? –  Feb 02 '16 at 16:48
  • In fact, you're free to choose the file name you want. You can then use it when importing it (without the extension): `import {ArraySortPipe} from './pipe-comoponent';` for example. – Thierry Templier Feb 02 '16 at 16:55
  • please check again the question, I've edited it with few things that I don't understand. –  Feb 02 '16 at 17:27
  • The `arrays` parameter is what you have in entry (your list for example) and `args` corresponds to parameter of the pipe (with `sort:someObj` -> `args` = `someObj`) – Thierry Templier Feb 02 '16 at 18:04
  • With this second parameter, you can pass `'completed'` to the `transform` method of your pipe ;-) – Thierry Templier Feb 02 '16 at 18:05
  • I still don't get what I have to do, how should i call sort? should i modify any parameter, I really don't understand. thank you –  Feb 02 '16 at 22:27
  • 1
    Unfortunately the plunker is deprecated. Thierry? –  Dec 12 '16 at 12:29
  • 4
    the `pipes: [..]` declaration is no longer valid (and no longer necessary) – phil294 Jan 30 '17 at 18:33
  • I down-voted this answer because it's an anti-pattern that others like Vitali have metioned before. https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe. See the discussion here https://stackoverflow.com/questions/46780843/angular-4-filter-search-custom-pipe and DeborahK's answer on how to handle this inside your component. – sfors says reinstate Monica May 25 '18 at 17:06
12

Updated OrderByPipe: fixed not sorting strings.

create a OrderByPipe class:

import { Pipe, PipeTransform } from "@angular/core";
@Pipe( {
name: 'orderBy'
} )
export class OrderByPipe implements PipeTransform {
transform( array: Array<any>, orderField: string, orderType: boolean ): Array<string> {
    array.sort( ( a: any, b: any ) => {
        let ae = a[ orderField ];
        let be = b[ orderField ];
        if ( ae == undefined && be == undefined ) return 0;
        if ( ae == undefined && be != undefined ) return orderType ? 1 : -1;
        if ( ae != undefined && be == undefined ) return orderType ? -1 : 1;
        if ( ae == be ) return 0;
        return orderType ? (ae.toString().toLowerCase() > be.toString().toLowerCase() ? -1 : 1) : (be.toString().toLowerCase() > ae.toString().toLowerCase() ? -1 : 1);
    } );
    return array;
  }
}

in your controller:

@Component({
pipes: [OrderByPipe]
})

or in your

 declarations: [OrderByPipe]

in your html:

<tr *ngFor="let obj of objects | orderBy : ObjFieldName: OrderByType">

ObjFieldName: object field name you want to sort;

OrderByType: boolean; true: descending order; false: ascending;

GuoJunjun
  • 331
  • 5
  • 11
10

Angular doesn't come with an orderBy filter out of the box, but if we decide we need one we can easily make one. There are however some caveats we need to be aware of to do with speed and minification. See below.

A simple pipe would look something like this.

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

@Pipe({
  name: 'sort'
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

This pipe accepts a sort function (fn), and gives it a default value that will sort an array of primitives in a sensible way. We have the option of overriding this sort function if we wish.

It does not accept an attribute name as a string, because attribute names are subject to minification. They will change when we minify our code, but minifiers are not smart enough to also minify the value in the template string.

Sorting primitives (numbers and strings)

We could use this to sort an array of numbers or strings using the default comparator:

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{numbers | sort}}
    {{strings | sort}}
  `
})
export class CatComponent
  numbers:Array<number> = [1,7,5,6]
  stringsArray<string> = ['cats', 'hats', 'caveats']
}

Sorting an array of objects

If we want to sort an array of objects, we can give it a comparator function.

import { Component } from '@angular/core';

@Component({
  selector: 'cat',
  template: `
    {{cats | sort:byName}}
  `
})
export class CatComponent
  cats:Array<Cat> = [
    {name: "Missy"},
    {name: "Squoodles"},
    {name: "Madame Pompadomme"}
  ]
  byName(a,b) {
    return a.name > b.name ? 1 : -1
  }
}

Caveats - pure vs. impure pipes

Angular 2 has a concept of pure and impure pipes.

A pure pipe optimises change detection using object identity. This means that the pipe will only run if the input object changes identity, for example if we add a new item to the array. It will not descent into objects. This means that if we change a nested attribute: this.cats[2].name = "Fluffy" for example, the pipe will not rerun. This helps Angular to be fast. Angular pipes are pure by default.

An impure pipe on the other hand will check object attributes. This potentially makes it much slower. Because it can't guarantee what the pipe function will do (perhaps it sortd differently based on the time of day for example), an impure pipe will run every time an asynchronous event occurs. This will slow down your app considerably if the array is large.

The pipe above is pure. This means it will only run when the objects in the array are immutable. If you change a cat, you must replace the entire cat object with a new one.

this.cats[2] = {name:"Tomy"}

We can change the above to an impure pipe by setting the pure attribute:

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

@Pipe({
  name: 'sort',
  pure: false
})
export class SortPipe implements PipeTransform {
  transform(ary: any, fn: Function = (a,b) => a > b ? 1 : -1): any {
    return ary.sort(fn)
  }
}

This pipe will descend into objects, but will be slower. Use with caution.

superluminary
  • 47,086
  • 25
  • 151
  • 148
  • Thanks.. Helped a lot. But one question.. If we should not use pipe or filter for sorting, **what is the best approach?** I searched everywhere, everybody is giving solution by creating pipe. – Pavankumar Shukla Jun 18 '18 at 13:16
  • @PavanShukla You can use a pipe, just make sure your array entries are immutable and create a pure pipe. Or, if you don't have a big array, make an impure pipe and sort each render. Alternately, create a sorted array as an attribute of your component and render that. – superluminary Jun 21 '18 at 12:50
  • I've used array.sort logic on click of each cloumn heading. I am doing this operation on the display data array.. is it good way? – Pavankumar Shukla Jun 21 '18 at 13:04
7

I've created an OrderBy pipe that does just what you need. It supports being able to sort on multiple columns of an enumerable of objects as well.

<li *ngFor="#todo in todos | orderBy : ['completed']">{{todo.name}} {{todo.completed}}</li>

This pipe does allow for adding more items to the array after rendering the page, and will sort the array with the updates dynamically.

I have a write up on the process here.

And here's a working demo: http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby and https://plnkr.co/edit/DHLVc0?p=info

Cory Shaw
  • 1,130
  • 10
  • 16
5

Recommend u use lodash with angular, then your pipe will be next:

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 _.sortBy(array, [args]);
    }

}

and use it in html like

*ngFor = "#todo of todos | orderBy:'completed'"

and don't forget add Pipe to your module

@NgModule({
    ...,
    declarations: [OrderByPipe, ...],
    ...
})
  • I like your approach Александр Петрик but I prefer to send array on template: orderBy: [ 'field1', 'field2' ] And then call on the pipe: return _.sortBy(array, args); – Eric Mar 16 '17 at 10:57
  • 1
    The problem of using _.sortBy is that you can't specify descendent order. I've found that using _.orderBy you can specify custom order for every field. i.e: _.orderBy(array, ['field1', 'field2'], ['asc', 'desc']) – Eric Mar 16 '17 at 11:22
4

This will work for any field you pass to it. (IMPORTANT: It will only order alphabetically so if you pass a date it will order it as alphabet not as date)

/*
 *      Example use
 *      Basic Array of single type: *ngFor="let todo of todoService.todos | orderBy : '-'"
 *      Multidimensional Array Sort on single column: *ngFor="let todo of todoService.todos | orderBy : ['-status']"
 *      Multidimensional Array Sort on multiple columns: *ngFor="let todo of todoService.todos | orderBy : ['status', '-title']"
 */

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

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

    value: string[] = [];

    static _orderByComparator(a: any, b: any): number {

        if (a === null || typeof a === "undefined") { a = 0; }
        if (b === null || typeof b === "undefined") { b = 0; }

        if (
            (isNaN(parseFloat(a)) ||
            !isFinite(a)) ||
            (isNaN(parseFloat(b)) || !isFinite(b))
        ) {
            // Isn"t a number so lowercase the string to properly compare
            a = a.toString();
            b = b.toString();
            if (a.toLowerCase() < b.toLowerCase()) { return -1; }
            if (a.toLowerCase() > b.toLowerCase()) { return 1; }
        } else {
            // Parse strings as numbers to compare properly
            if (parseFloat(a) < parseFloat(b)) { return -1; }
            if (parseFloat(a) > parseFloat(b)) { return 1; }
        }

        return 0; // equal each other
    }

    public transform(input: any, config = "+"): any {
        if (!input) { return input; }

        // make a copy of the input"s reference
        this.value = [...input];
        let value = this.value;
        if (!Array.isArray(value)) { return value; }

        if (!Array.isArray(config) || (Array.isArray(config) && config.length === 1)) {
            let propertyToCheck: string = !Array.isArray(config) ? config : config[0];
            let desc = propertyToCheck.substr(0, 1) === "-";

            // Basic array
            if (!propertyToCheck || propertyToCheck === "-" || propertyToCheck === "+") {
                return !desc ? value.sort() : value.sort().reverse();
            } else {
                let property: string = propertyToCheck.substr(0, 1) === "+" || propertyToCheck.substr(0, 1) === "-"
                    ? propertyToCheck.substr(1)
                    : propertyToCheck;

                return value.sort(function(a: any, b: any) {
                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    return !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);
                });
            }
        } else {
            // Loop over property of the array in order and sort
            return value.sort(function(a: any, b: any) {
                for (let i = 0; i < config.length; i++) {
                    let desc = config[i].substr(0, 1) === "-";
                    let property = config[i].substr(0, 1) === "+" || config[i].substr(0, 1) === "-"
                        ? config[i].substr(1)
                        : config[i];

                    let aValue = a[property];
                    let bValue = b[property];

                    let propertySplit = property.split(".");

                    if (typeof aValue === "undefined" && typeof bValue === "undefined" && propertySplit.length > 1) {
                        aValue = a;
                        bValue = b;
                        for (let j = 0; j < propertySplit.length; j++) {
                            aValue = aValue[propertySplit[j]];
                            bValue = bValue[propertySplit[j]];
                        }
                    }

                    let comparison = !desc
                        ? OrderByPipe._orderByComparator(aValue, bValue)
                        : -OrderByPipe._orderByComparator(aValue, bValue);

                    // Don"t return 0 yet in case of needing to sort by next property
                    if (comparison !== 0) { return comparison; }
                }

                return 0; // equal each other
            });
        }
    }
}
CommonSenseCode
  • 23,522
  • 33
  • 131
  • 186
4

You can use this for objects:

@Pipe({
  name: 'sort',
})
export class SortPipe implements PipeTransform {

  transform(array: any[], field: string): any[] {
    return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0);
  }

}
Andre Coetzee
  • 1,260
  • 3
  • 20
  • 34
3

This is good replacement for AngularJs orderby pipe in angular 4. Easy and simple to use.

This is github URL for more information https://github.com/VadimDez/ngx-order-pipe

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

@Pipe({
  name: 'orderBy'
})
export class OrderPipe implements PipeTransform {

  transform(value: any | any[], expression?: any, reverse?: boolean): any {
    if (!value) {
      return value;
    }

    const isArray = value instanceof Array;

    if (isArray) {
      return this.sortArray(value, expression, reverse);
    }

    if (typeof value === 'object') {
      return this.transformObject(value, expression, reverse);
    }

    return value;
  }

  /**
   * Sort array
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private sortArray(value: any[], expression?: any, reverse?: boolean): any[] {
    const isDeepLink = expression && expression.indexOf('.') !== -1;

    if (isDeepLink) {
      expression = OrderPipe.parseExpression(expression);
    }

    let array: any[] = value.sort((a: any, b: any): number => {
      if (!expression) {
        return a > b ? 1 : -1;
      }

      if (!isDeepLink) {
        return a[expression] > b[expression] ? 1 : -1;
      }

      return OrderPipe.getValue(a, expression) > OrderPipe.getValue(b, expression) ? 1 : -1;
    });

    if (reverse) {
      return array.reverse();
    }

    return array;
  }


  /**
   * Transform Object
   *
   * @param value
   * @param expression
   * @param reverse
   * @returns {any[]}
   */
  private transformObject(value: any | any[], expression?: any, reverse?: boolean): any {
    let parsedExpression = OrderPipe.parseExpression(expression);
    let lastPredicate = parsedExpression.pop();
    let oldValue = OrderPipe.getValue(value, parsedExpression);

    if (!(oldValue instanceof Array)) {
      parsedExpression.push(lastPredicate);
      lastPredicate = null;
      oldValue = OrderPipe.getValue(value, parsedExpression);
    }

    if (!oldValue) {
      return value;
    }

    const newValue = this.transform(oldValue, lastPredicate, reverse);
    OrderPipe.setValue(value, newValue, parsedExpression);
    return value;
  }

  /**
   * Parse expression, split into items
   * @param expression
   * @returns {string[]}
   */
  private static parseExpression(expression: string): string[] {
    expression = expression.replace(/\[(\w+)\]/g, '.$1');
    expression = expression.replace(/^\./, '');
    return expression.split('.');
  }

  /**
   * Get value by expression
   *
   * @param object
   * @param expression
   * @returns {any}
   */
  private static getValue(object: any, expression: string[]) {
    for (let i = 0, n = expression.length; i < n; ++i) {
      const k = expression[i];
      if (!(k in object)) {
        return;
      }
      object = object[k];
    }

    return object;
  }

  /**
   * Set value by expression
   *
   * @param object
   * @param value
   * @param expression
   */
  private static setValue(object: any, value: any, expression: string[]) {
    let i;
    for (i = 0; i < expression.length - 1; i++) {
      object = object[expression[i]];
    }

    object[expression[i]] = value;
  }
}
ganesh kalje
  • 3,014
  • 2
  • 16
  • 12
2

As we know filter and order by are removed from ANGULAR 2 and we need to write our own, here is a good example on plunker and detailed article

It used both filter as well as orderby, here is the code for order pipe

import { Pipe, PipeTransform } from '@angular/core';    
@Pipe({  name: 'orderBy' })
export class OrderrByPipe implements PipeTransform {

  transform(records: Array<any>, args?: any): any {       
    return records.sort(function(a, b){
          if(a[args.property] < b[args.property]){
            return -1 * args.direction;
          }
          else if( a[args.property] > b[args.property]){
            return 1 * args.direction;
          }
          else{
            return 0;
          }
        });
    };
 }
Ali Adravi
  • 21,707
  • 9
  • 87
  • 85
2

In package.json, add something like (This version is ok for Angular 2):

  "ngx-order-pipe": "^1.1.3",

In your typescript module (and imports array):

  import { OrderModule } from 'ngx-order-pipe';
Vince
  • 544
  • 5
  • 15
1

For Angular 5+ Version we can use ngx-order-pipe package

Source Tutorial Link

Install package

$ npm install ngx-order-pipe --save

Import in apps module

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { OrderModule } from 'ngx-order-pipe';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    OrderModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

use anywhere

  <ul>
    <li *ngFor="let item of (dummyData | orderBy:'name') ">
      {{item.name}}
    </li>
  </ul>
Code Spy
  • 9,626
  • 4
  • 66
  • 46
0

In the current version of Angular2, orderBy and ArraySort pipes are not supported. You need to write/use some custom pipes for this.

Siva
  • 2,735
  • 16
  • 14
0

orderby Pipe in Angular JS will support but Angular (higher versions) will not support . Please find he details discussed to increase performance speed its obsolete.

https://angular.io/guide/styleguide#do-not-add-filtering-and-sorting-logic-to-pipes

Alex Panchenko
  • 452
  • 2
  • 6
Rahul Uttarkar
  • 3,367
  • 3
  • 35
  • 40
0
<!-- const cars=['Audi','Merc','BMW','Volvo','Tesla'] -->

<ul>
  <li *ngFor="let car of cars">{{car}}</li>
</ul>


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

@Pipe({ name: 'sortBy' })
export class SortByPipe implements PipeTransform {

  transform(value: any[], order = '', column: string = ''): any[] {
    if (!value || order === '' || !order) { return value; } // no array
    if (!column || column === '') { return sortBy(value); } // sort 1d array
    if (value.length <= 1) { return value; } // array with only one item
    return orderBy(value, [column], [order]);
  }
}
Abdo-Host
  • 2,470
  • 34
  • 33
0

Adding to Vitali's response, the old documentation about /pipes#appendix-no-filterpipe-or-orderbypipe is no longer available for some reason. It is being discussed here: https://github.com/angular/angular/issues/41652.

Alejandro L.
  • 43
  • 1
  • 6
0

Here is @Sal's answer with:

  • Better TypeScript typing
  • Support for arrays of primitives (call without passing in sortKey)
  • input array doesn't get mutated

NOTE: I also removed the Array.isArray() error check.

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

@Pipe({
  name: 'sort'
})
export class SortPipe implements PipeTransform {
  transform<T, K extends keyof T>(input: T[], sortKey?: K): T[] {
    return [...input].sort((a: T, b: T) => {
      const aValue = typeof a === 'object'
        ? a[sortKey]
        : a;
      const bValue = typeof b === 'object'
        ? b[sortKey]
        : b;

      if (aValue < bValue) {
        return -1;
      } else if (aValue > bValue) {
        return 1;
      }

      return 0;
    });
  }
}
JWess
  • 602
  • 7
  • 17
-1
Component template:
todos| sort: ‘property’:’asc|desc’

Pipe code:

import { Pipe,PipeTransform  } from "angular/core";
import {Todo} from './todo';

@Pipe({
  name: "sort"
})
export class TodosSortPipe implements PipeTransform {
  transform(array: Array<Todo>, args: string): Array<Todo> {
    array.sort((a: any, b: any) => {
      if (a < b) {
        return -1;
      } else if (a > b) {
        return 1;
      } else {`enter code here`
        return 0;
      }
    });
    return array;
  }
}
sonal jain
  • 14
  • 1