Order pipe production

I cannot translate this code from Angualr 1 to Angular 2:

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

Here is what I did after Thierry Templier answered:

Template Component:

 *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 am trying to sort an array of Todo s ordered by the completed property. First, todo.completed = false and then todo.complete = true .

I do not understand the transform method very well and how to pass arguments in this method and in the sort method.

What is args: string ? What is a and b and where do they come from?

+90
angular pipe angular2-template angular-pipe
Feb 02 '16 at 16:31
source share
17 answers

I modified @Thierry Templier's answer so that the channel 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 use this:

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

Hope this helps someone.

+69
Jun 13 '17 at 2:07 on
source share

Please see https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe for a full discussion. This quote is most relevant. In fact, for large-scale applications that must be actively minimized, the filtering and sorting logic must move into the component itself.

โ€œSome of us may not care about aggressively minimizing this. It's our choice. But the Angular product should not stop anyone from aggressively minimizing it. Therefore, the Angular team decided that everything that comes with Angular would be minimized safely.

The Angular team and many experienced Angular developers strongly recommend moving the filtering and sorting logic into the component itself. A component can provide a FilterHeroes or sortedHeroes property and control when and how often auxiliary logic should be executed. Any features that you could add to the channel and use in the application can be written to the filtering / sorting service and implemented in the component. "

+66
Jul 08 '16 at 10:50
source share

You can implement a custom channel for this that uses 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 this channel as described below. Do not forget to specify your pipe in the component's pipes attribute:

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

This is a simple example of arrays with string values, but you can have some advanced sorting processing (based on the attributes of an object in the case of an array of objects, based on sorting options, ...).

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

Hope this helps you, Thierry

+37
Feb 02 '16 at 16:32
source share

Updated OrderByPipe: fixed not sorting strings.

create class OrderByPipe:

 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

  declarations: [OrderByPipe] 

in your html:

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

ObjFieldName: the name of the field of the object you want to sort;

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

+9
Jul 27 '16 at 12:03
source share

Angular does not come with an orderBy filter out of the box, but if we decide what we need, we can easily create it. However, there are some caveats we need to know about speed and minimum. See below.

A simple pipe will 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 tube takes a sort function ( fn ) and gives it a default value that will sort the array of primitives in a reasonable way. We have the ability to override this sorting function if we want.

It does not accept the attribute name as a string, because attribute names are to be specified. They will change when we minimize our code, but minifiers are not smart enough to also minimize 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'] } 

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

Cautions - Clean and Unclean Pipes

Angular 2 has the concept of clean and unclean pipes.

A clean pipe optimizes change detection using an object identifier. This means that the channel will only work if the input object changes its identifier, for example, if we add a new element to the array. He will not descend into objects. This means that if we change the nested attribute: this.cats[2].name = "Fluffy" , for example, the pipe will not be restarted. This helps Angular to be fast. Angular is clean by default.

An unclean pipe , on the other hand, will check the attributes of an object. This potentially makes it much slower. Since it cannot guarantee that the pipe function will work (it may be sorted differently depending on the time of day), an unclean channel will be triggered every time an asynchronous event occurs. This will significantly slow down your application if the array is large.

The pipe on top is clean. This means that it will only work when the objects in the array are immutable. If you change the cat, you must replace the entire cat object with a new one.

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

We can change the above to an unclean channel by setting a clean 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 sink into objects, but will be slower. Use with caution.

+8
May 16 '17 at 9:52 pm
source share

I created an OrderBy channel that does exactly what you need. It supports the ability to sort by multiple columns of an enumerated object.

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

This channel allows you to add additional elements to the array after rendering the page and sort the array with updates dynamically.

I have a write process here .

And here is a working demo: http://fuelinteractive.imtqy.com/fuel-ui/#/pipe/orderby and https://plnkr.co/edit/DHLVc0?p=info

+7
Apr 12 '16 at 13:07 on
source share

We recommend using lodash with angular, then your pipe will be as follows:

 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 for example

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

and don't forget to add a pipe to your module

 @NgModule({ ..., declarations: [OrderByPipe, ...], ... }) 
+4
Mar 14 '17 at 9:00
source share

This will work for any field that you pass to it. ( IMPORTANT: It will indicate only in alphabetical order, so if you pass the date, it will order it as an alphabet, not as a 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"ta 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 }); } } } 
+3
Sep 22 '16 at 23:38
source share

This is a good replacement for AngularJs orderby tube in angular 4 . Simple and easy to use.

This is the 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; } } 
+3
Oct 11 '17 at 7:43 on
source share

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

He used both filter and orderby, here is the code for the order

 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; } }); }; } 
+2
Apr 16 '17 at 15:54 on
source share

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); } } 
+2
Feb 04 '18 at 20:11
source share

In package.json add something like (this version is suitable for Angular 2):

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

In your typescript module (and import array):

  import { OrderModule } from 'ngx-order-pipe'; 
+1
04 Oct. '18 at 19:18
source share

In the current version of Angular2, orderBy and ArraySort channels are not supported. To do this, you need to write / use some custom channels for this.

0
Feb 02 '16 at 16:41
source share

Created tube for sorting. It accepts both a string and an array of strings, sorting by several values.

 @Pipe({name: 'orderBy'}) export class OrderBy implements PipeTransform { transform(array: any[], filter: any): any[] { if(typeof filter === 'string') { return this.sortAray(array, filter) } else { for (var i = filter.length -1; i >= 0; i--) { array = this.sortAray(array, filter[i]); } return array; } } private sortAray(array, field) { return array.sort((a, b) => a[field].toLowerCase() !== b[field].toLowerCase() ? a[field].toLowerCase() < b[field].toLowerCase() ? -1 : 1 : 0); } } 
0
Jun 20 '19 at 12:11
source share

pipe orderby in Angular JS will support, but Angular (later versions) will not support . Please find the details discussed to increase its speed.

https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe

0
Aug 16 '19 at 5:34
source share

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

Tutorial Link

Install package

 $ npm install ngx-order-pipe --save 

Import to application 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> 
-one
Dec 27 '18 at 11:18
source share
 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; } } 
-one
Jul 26 '19 at 3:54
source share



All Articles