20

I am looking into how to filter an array of data in Angular2.

I looked into using a custom pipe, but I feel this is not what I am looking for, as it seems more geared towards simple presentation transformations rather then filtering large sets of data.

The array is set out as follows:

getLogs(): Array<Logs> {
        return [
            { id: '1', plate: 'plate1', time: 20 },
            { id: '1', plate: 'plate2', time: 30 },
            { id: '1', plate: 'plate3', time: 30 },
            { id: '2', plate: 'plate4', time: 30 },
            { id: '2', plate: 'plate5', time: 30 },
            { id: '2', plate: 'plate6', time: 30 }
        ];
    }

I want to filter this by id. So when I enter "1" into a search bar, it updates to display the corresponding values.

If there is a method on how to do this, I would love to know!

Witted
  • 422
  • 1
  • 4
  • 14

2 Answers2

36

There is no way to do that using a default pipe. Here is the list of supported pipes by default: https://github.com/angular/angular/blob/master/modules/angular2/src/common/pipes/common_pipes.ts.

That said you can easily add a pipe for such use case:

import {Injectable, Pipe} from 'angular2/core';

@Pipe({
    name: 'myfilter'
})
@Injectable()
export class MyFilterPipe implements PipeTransform {
    transform(items: any[], args: any[]): any {
        return items.filter(item => item.id.indexOf(args[0]) !== -1);
    }
}

And use it:

import { MyFilterPipe } from './filter-pipe';
(...)

@Component({
  selector: 'my-component',
  pipes: [ MyFilterPipe ],
  template: `
    <ul>
      <li *ngFor="#element of (elements | myfilter:'123')">(...)</li>
    </ul>
  `
})

Hope it helps you, Thierry

Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • what does the implementation of PipeTransform do? Im a little confused as to its purpose. – Witted Dec 22 '15 at 14:58
  • In fact, when you want to implement a pipe, you need to implement this interface and put your processing in the `transform` method. See the corresponding documentation for more details: https://angular.io/docs/ts/latest/api/core/PipeTransform-interface.html. Its first parameter correspond to the list itself and the second one to element(s) to use to filter your list... – Thierry Templier Dec 22 '15 at 15:01
  • Thanks for the explanation. Last question is it possible to make the output from *ngFor="#element of (elements | myfilter:'123') a variable? – Witted Dec 22 '15 at 15:15
  • Yes, it's possible ;-) The only thing to be careful is that the elements list is there if it's loaded using HTTP for example... – Thierry Templier Dec 22 '15 at 15:17
  • I have been hunting for a method to do this without much luck. Can you point me in the right direction? Would really appreciate it – Witted Dec 22 '15 at 15:48
  • In fact, I see two things right now. The use of the async pipe (https://angular.io/docs/ts/latest/api/common/AsyncPipe-class.html) or having an ngIf to display to whole loop when the data is there. In the future, it would be great to use the resolve-like feature (https://github.com/angular/angular/issues/4015) but it's not implemented yet... – Thierry Templier Dec 23 '15 at 08:40
  • @ThierryTemplier Do we really need to keep both Pipe & Injectable decorators ? – SaiKiran Mandhala Aug 09 '17 at 09:41
  • I get an error about `pipes` field not present in `@Component` annotation – theShadow89 Sep 20 '17 at 11:08
5

I have a similar scenario in one of my samples

<input "(keyup)="navigate($event)" />

<div *ngFor="#row of visibleRows"></div>    

......

navigate($event){
        this.model.navigate($event.keyCode);
        this.visibleRows = this.getVisibleRows();
}

getVisibleRows(){
    return this.model.rows.filter((row) => row.rowIndex >= this.model.start && row.rowIndex < this.model.end);
}

My approach is to recalculate the array on some qualifying event. In my case it's keyup. It may seem convenient to bind to a function or filter, but it's recommended to bind to the array directly instead. This is because the change tracking will get confused since the function/filter will return a new array instance every time change tracking is triggered - regardless of what triggered it.

Here is the full source: https://github.com/thelgevold/angular-2-samples/tree/master/components/spreadsheet

I also have a demo: http://www.syntaxsuccess.com/angular-2-samples/#/demo/spreadsheet

TGH
  • 38,769
  • 12
  • 102
  • 135
  • Ive actually found your github very helpful already so thank you! My table in what im working on is based quite heavily on your grid using: to build the array into a table. its been a massive help in a new and sparsely documented language. This doesn't really have much relevance to the question but more a personal thanks. – Witted Dec 22 '15 at 14:38
  • Thanks! I am glad you find the samples helpful – TGH Dec 22 '15 at 16:01
  • "the change tracking will get confused since the function/filter will return a new array instance every time change tracking is triggered" -- very true, but you could return the same array instance each time if you use a stateful pipe. Or, if your component allows it, you could use the `onPush` change detection strategy in conjunction with a stateful pipe. I discuss both options in [this SO answer](http://stackoverflow.com/a/34497504/215945). – Mark Rajcok Dec 28 '15 at 18:13