angular 2 sort and filter

In Angularjs 1 it is possible to sort and filter the following way:

<ul ng-repeat="friend in friends | filter:query | orderBy: 'name' ">
<li>{{friend.name}}</li>
</ul>

But I could not find any examples of how to do this in Angularjs 2.0. My question is how to sort and filter in Angularjs 2.0? If it is still not supported, does anyone know when or if it will be put into Angularjs 2.0?

220613 次浏览

You must create your own Pipe for array sorting, here is one example how can you do that.

<li *ngFor="#item of array | arraySort:'-date'">\{\{item.name}} \{\{item.date | date:'medium' }}</li>

https://plnkr.co/edit/DU6pxr?p=preview

Here is a simple filter pipe for array of objects that contain attributes with string values (ES6)

filter-array-pipe.js

import {Pipe} from 'angular2/core';


// # Filter Array of Objects
@Pipe({ name: 'filter' })
export class FilterArrayPipe {
transform(value, args) {
if (!args[0]) {
return value;
} else if (value) {
return value.filter(item => {
for (let key in item) {
if ((typeof item[key] === 'string' || item[key] instanceof String) &&
(item[key].indexOf(args[0]) !== -1)) {
return true;
}
}
});
}
}
}

Your component

myobjComponent.js

import {Component} from 'angular2/core';
import {HTTP_PROVIDERS, Http} from 'angular2/http';
import {FilterArrayPipe} from 'filter-array-pipe';


@Component({
templateUrl: 'myobj.list.html',
providers: [HTTP_PROVIDERS],
pipes: [FilterArrayPipe]
})
export class MyObjList {
static get parameters() {
return [[Http]];
}
constructor(_http) {
_http.get('/api/myobj')
.map(res => res.json())
.subscribe(
data => this.myobjs = data,
err => this.logError(err))
);
}
resetQuery(){
this.query = '';
}
}

In your template

myobj.list.html

<input type="text" [(ngModel)]="query" placeholder="... filter" >
<div (click)="resetQuery()"> <span class="icon-cross"></span> </div>
</div>
<ul><li *ngFor="#myobj of myobjs| filter:query">...<li></ul>

This isn't added out of the box because the Angular team wants Angular 2 to run minified. OrderBy runs off of reflection which breaks with minification. Check out Miško Heverey's response on the matter.

I've taken the time to create an OrderBy pipe that supports both single and multi-dimensional arrays. It also supports being able to sort on multiple columns of the multi-dimensional array.

<li *ngFor="let person of people | orderBy : ['-lastName', 'age']">\{\{person.firstName}} \{\{person.lastName}}, \{\{person.age}}</li>

This pipe does allow for adding more items to the array after rendering the page, and still sort the arrays with the new items correctly.

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

EDIT: Added new demo to http://fuelinteractive.github.io/fuel-ui/#/pipe/orderby

EDIT 2: Updated ngFor to new syntax

A pipe takes in data as input and transforms it to a desired output. Add this pipe file:orderby.ts inside your /app folder .

orderby.ts

//The pipe class implements the PipeTransform interface's transform method that accepts an input value and an optional array of parameters and returns the transformed value.


import { Pipe,PipeTransform } from "angular2/core";


//We tell Angular that this is a pipe by applying the @Pipe decorator which we import from the core Angular library.


@Pipe({


//The @Pipe decorator takes an object with a name property whose value is the pipe name that we'll use within a template expression. It must be a valid JavaScript identifier. Our pipe's name is orderby.


name: "orderby"
})


export class OrderByPipe implements PipeTransform {
transform(array:Array<any>, args?) {


// Check if array exists, in this case array contains articles and args is an array that has 1 element : !id


if(array) {


// get the first element


let orderByValue = args[0]
let byVal = 1


// check if exclamation point


if(orderByValue.charAt(0) == "!") {


// reverse the array


byVal = -1
orderByValue = orderByValue.substring(1)
}
console.log("byVal",byVal);
console.log("orderByValue",orderByValue);


array.sort((a: any, b: any) => {
if(a[orderByValue] < b[orderByValue]) {
return -1*byVal;
} else if (a[orderByValue] > b[orderByValue]) {
return 1*byVal;
} else {
return 0;
}
});
return array;
}
//
}
}

In your component file (app.component.ts) import the pipe that you just added using: import {OrderByPipe} from './orderby';

Then, add *ngFor="#article of articles | orderby:'id'" inside your template if you want to sort your articles by id in ascending order or orderby:'!id'" in descending order.

We add parameters to a pipe by following the pipe name with a colon ( : ) and then the parameter value

We must list our pipe in the pipes array of the @Component decorator. pipes: [ OrderByPipe ] .

app.component.ts

import {Component, OnInit} from 'angular2/core';
import {OrderByPipe} from './orderby';


@Component({
selector: 'my-app',
template: `
<h2>orderby-pipe by N2B</h2>
<p *ngFor="#article of articles | orderby:'id'">
Article title : \{\{article.title}}
</p>
`,
pipes: [ OrderByPipe ]


})
export class AppComponent{
articles:Array<any>
ngOnInit(){
this.articles = [
{
id: 1,
title: "title1"
},{
id: 2,
title: "title2",
}]
}


}

More info here on my github and this post on my website

This is my sort. It will do number sort , string sort and date sort .

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


@Pipe({
name: 'sortPipe'
})


export class SortPipe implements PipeTransform {


transform(array: Array<string>, key: string): Array<string> {


console.log("Entered in pipe*******  "+ key);




if(key === undefined || key == '' ){
return array;
}


var arr = key.split("-");
var keyString = arr[0];   // string or column name to sort(name or age or date)
var sortOrder = arr[1];   // asc or desc order
var byVal = 1;




array.sort((a: any, b: any) => {


if(keyString === 'date' ){


let left    = Number(new Date(a[keyString]));
let right   = Number(new Date(b[keyString]));


return (sortOrder === "asc") ? right - left : left - right;
}
else if(keyString === 'name'){


if(a[keyString] < b[keyString]) {
return (sortOrder === "asc" ) ? -1*byVal : 1*byVal;
} else if (a[keyString] > b[keyString]) {
return (sortOrder === "asc" ) ? 1*byVal : -1*byVal;
} else {
return 0;
}
}
else if(keyString === 'age'){
return (sortOrder === "asc") ? a[keyString] - b[keyString] : b[keyString] - a[keyString];
}


});


return array;


}


}

It is not supported by design. The sortBy pipe can cause real performance issues for a production scale app. This was an issue with angular version 1.

You should not create a custom sort function. Instead, you should sort your array first in the typescript file and then display it. If the order needs to be updated when for example a dropdown is selected then have this dropdown selection trigger a function and call your sort function called from that. This sort function can be extracted to a service so that it can be re-used. This way, the sorting will only be applied when it is required and your app performance will be much better.