Search code examples
angulartypescriptangular2-pipe

My custom pipe (filter) does not work in Angular 2


I have my own pipe created for filtering over any field in my table. When I put a string into search box it prints 'found' correctly in my console but no rows are displayed in the table. When I remove a pipe completely, everything works fine, table contains all records.

import { Component, Input, OnInit } from '@angular/core';
import { MyTableData } from '../interfaces/my-table-data.interface'

@Component({
    selector: 'my-table',
    template: `
    <div style="width: 100%">
        <div style="float: left; height: 50px; width: 100%">
            Search: <input type="text" [(ngModel)]="filterValue" style="height: 30px; border: 1px solid silver"/>
        </div>
        <div style="float: left; width: 100%">
            <table>
                <tr *ngFor="let row of data.rows | myTableFilter:filterValue">
                    <td *ngFor="let value of row">{{value}}</td>
                </tr>
            </table>
        </div>
    </div>
    `
})
export class MyTableComponent implements OnInit { 
    @Input() data: MyTableData;
    filterValue: string;

    ngOnInit() {

    }
}  

and pipe:

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

@Pipe({
    name: 'myTableFilter',
    pure: false
})
@Injectable()
export class MyTableFilterPipe implements PipeTransform {
    transform(items: any[], arg: string): any {
        if(arg == '') return true;

        items.filter(item => {
            for(let value of item) {
                if(String(value).indexOf(arg) !== -1) {   
                    console.log('found match') //it prints correctly
                    return true;
                }
            }
            return false;
        });
    };
}

Regards


Solution

  • A pipe is a pipe, and not really a filter. It's used to alter the input. Your input in this case is the array data.rows and you want to only show rows matching a certain input argument filterValue. In that case you want to return the filtered array, and not a true or false value. On the other hand, you should really keep your pipe pure, because.. this is a pure pipe. It only changes if the input changes (filterValue):

    @Pipe({
        name: 'myTableFilter'
    })
    @Injectable()
    export class MyTableFilterPipe implements PipeTransform {
        transform(items: any[], filterValue: string): any {
            if(!items) {
              return [];
            }
            if(!filterValue) {
              return items;
            }
            return items.filter(item => {
                for(let value of item) {
                    if(String(value).indexOf(filterValue) !== -1) {   
                        return true;
                    }
                }              
            });
        };
    }