Angular 4 Pipe Filter

The transform method signature changed somewhere in an RC of Angular 2. Try something more like this:

export class FilterPipe implements PipeTransform {
    transform(items: any[], filterBy: string): any {
        return items.filter(item => item.id.indexOf(filterBy) !== -1);
    }
}

And if you want to handle nulls and make the filter case insensitive, you may want to do something more like the one I have here:

export class ProductFilterPipe implements PipeTransform {

    transform(value: IProduct[], filterBy: string): IProduct[] {
        filterBy = filterBy ? filterBy.toLocaleLowerCase() : null;
        return filterBy ? value.filter((product: IProduct) =>
            product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1) : value;
    }
}

And NOTE: Sorting and filtering in pipes is a big issue with performance and they are NOT recommended. See the docs here for more info: https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe


Pipes in Angular 2+ are a great way to transform and format data right from your templates.

Pipes allow us to change data inside of a template; i.e. filtering, ordering, formatting dates, numbers, currencies, etc. A quick example is you can transfer a string to lowercase by applying a simple filter in the template code.

List of Built-in Pipes from API List Examples

{{ user.name | uppercase }}

Example of Angular version 4.4.7. ng version


Custom Pipes which accepts multiple arguments.

HTML « *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] "
TS   « transform(json: any[], args: any[]) : any[] { ... }

Filtering the content using a Pipe « json-filter-by.pipe.ts

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

@Pipe({ name: 'jsonFilterBy' })
@Injectable()
export class JsonFilterByPipe implements PipeTransform {

  transform(json: any[], args: any[]) : any[] {
    var searchText = args[0];
    var jsonKey = args[1];

    // json = undefined, args = (2) [undefined, "name"]
    if(searchText == null || searchText == 'undefined') return json;
    if(jsonKey    == null || jsonKey    == 'undefined') return json;

    // Copy all objects of original array into new Array.
    var returnObjects = json;
    json.forEach( function ( filterObjectEntery ) {

      if( filterObjectEntery.hasOwnProperty( jsonKey ) ) {
        console.log('Search key is available in JSON object.');

        if ( typeof filterObjectEntery[jsonKey] != "undefined" && 
        filterObjectEntery[jsonKey].toLowerCase().indexOf(searchText.toLowerCase()) > -1 ) {
            // object value contains the user provided text.
        } else {
            // object didn't match a filter value so remove it from array via filter
            returnObjects = returnObjects.filter(obj => obj !== filterObjectEntery);
        }
      } else {
        console.log('Search key is not available in JSON object.');
      }

    })
    return returnObjects;
  }
}

Add to @NgModule « Add JsonFilterByPipe to your declarations list in your module; if you forget to do this you'll get an error no provider for jsonFilterBy. If you add to module then it is available to all the component's of that module.

@NgModule({
  imports: [
    CommonModule,
    RouterModule,
    FormsModule, ReactiveFormsModule,
  ],
  providers: [ StudentDetailsService ],
  declarations: [
    UsersComponent, UserComponent,

    JsonFilterByPipe,
  ],
  exports : [UsersComponent, UserComponent]
})
export class UsersModule {
    // ...
}

File Name: users.component.ts and StudentDetailsService is created from this link.

import { MyStudents } from './../../services/student/my-students';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { StudentDetailsService } from '../../services/student/student-details.service';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: [ './users.component.css' ],

  providers:[StudentDetailsService]
})
export class UsersComponent implements OnInit, OnDestroy  {

  students: MyStudents[];
  selectedStudent: MyStudents;

  constructor(private studentService: StudentDetailsService) { }

  ngOnInit(): void {
    this.loadAllUsers();
  }
  ngOnDestroy(): void {
    // ONDestroy to prevent memory leaks
  }

  loadAllUsers(): void {
    this.studentService.getStudentsList().then(students => this.students = students);
  }

  onSelect(student: MyStudents): void {
    this.selectedStudent = student;
  }

}

File Name: users.component.html

<div>
    <br />
    <div class="form-group">
        <div class="col-md-6" >
            Filter by Name: 
            <input type="text" [(ngModel)]="searchText" 
                   class="form-control" placeholder="Search By Category" />
        </div>
    </div>

    <h2>Present are Students</h2>
    <ul class="students">
    <li *ngFor="let student of students | jsonFilterBy:[searchText, 'name'] " >
        <a *ngIf="student" routerLink="/users/update/{{student.id}}">
            <span class="badge">{{student.id}}</span> {{student.name | uppercase}}
        </a>
    </li>
    </ul>
</div>

Here is a working plunkr with a filter and sortBy pipe. https://plnkr.co/edit/vRvnNUULmBpkbLUYk4uw?p=preview

As developer033 mentioned in a comment, you are passing in a single value to the filter pipe, when the filter pipe is expecting an array of values. I would tell the pipe to expect a single value instead of an array

export class FilterPipe implements PipeTransform {
    transform(items: any[], term: string): any {
        // I am unsure what id is here. did you mean title?
        return items.filter(item => item.id.indexOf(term) !== -1);
    }
}

I would agree with DeborahK that impure pipes should be avoided for performance reasons. The plunkr includes console logs where you can see how much the impure pipe is called.