Search code examples
angularangular-cliangular-pipe

Angular2 .filter is not a function


While following a tutorial to filter data using angular2 pipes, got below error

EXCEPTION: Error in ./PmProductsComponent class PmProductsComponent - inline template:20:28 caused by: value.filter is not a function

Is anyone able to shed some light as to why value.filter is not a function. It seems to align with the tutorials syntax, I am thinking perhaps an update came out that requires something different?

PIPE

import {PipeTransform, Pipe} from '@angular/core';
import {IProduct} from './product';

@Pipe( {
    name: 'productFilter'
})
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;
    }

}

Component:

import { Component, OnInit } from '@angular/core';
import {IProduct} from './product';

@Component({
  selector: 'app-pm-products',
  templateUrl: './pm-products.component.html',
  styleUrls: ['./pm-products.component.css']
})
export class PmProductsComponent implements OnInit {
  pageTitle: string = 'Product List';
  imageWidth: number = 50;
  imageMargin: number = 2;
  showImage: Boolean = false;
  listFilter: string = 'cart';
  products: IProduct[] = [
        {
        "productId": 1,
        "productName": "Leaf Rake",
        "productCode": "GDN-0011",
        "releaseDate": "March 19, 2016",
        "description": "Leaf rake with 48-inch wooden handle.",
        "price": 19.95,
        "starRating": 3.2,
        "imageUrl": "http://openclipart.org/image/300px/svg_to_png/26215/Anonymous_Leaf_Rake.png"
    },
    {
        "productId": 2,
        "productName": "Garden Cart",
        "productCode": "GDN-0023",
        "releaseDate": "March 18, 2016",
        "description": "15 gallon capacity rolling garden cart",
        "price": 32.99,
        "starRating": 4.2,
        "imageUrl": "http://openclipart.org/image/300px/svg_to_png/58471/garden_cart.png"
    },
  ]

  toggleImage() : void {
    this.showImage = !this.showImage;

  }
  constructor() { }

  ngOnInit() {
    console.log('In OnInit');
  }

}

HTML

<div class = 'panel panel-primary'>
  <div class = 'panel-heading'>
    {{pageTitle}}
  </div>
    <div class ='panel-body'>
            <div class = 'row'>
                <div class = 'col-md-2'> Filter by:</div>
                <div class = 'col-md-4'>
                    <input type = 'text' 
                    [(ngModel)]='listFilter'/>
                </div>
            </div>
            <div class = 'row'>
                <div class = 'col-md-6'>
                    <h3>Filtered by:{{listFilter}}</h3>
                </div>
            </div>

            <div class = 'table-responsive'>
                <table class = 'table' 
                            *ngIf='products && products.length | productFilter:listFilter'>
                    <thead>
                        <tr>
                            <th>
                                <button class = 'btn btn-primary'
                                (click) = 'toggleImage()'>
                                 {{showImage ? 'Hide' : 'Show'}} Image
                                </button>
                            </th>
                            <th>Products</th>
                            <th>Code</th>
                            <th>Available</th>
                            <th>Price</th>
                            <th>5 Star Rating</th>

                        </tr>
                    </thead>
                    <tbody>
                        <tr *ngFor='let item of products'>
                            <td>
                                <img *ngIf = 'showImage' [src] = 'item.imageUrl' 
                                    [title] = 'item.productName'
                                    [style.width.px]= 'imageWidth'
                                    [style.margin.px]= 'imageMargin'
                            >
                            </td>
                            <td>{{item.productName}}</td>
                            <td>{{item.productCode | lowercase}}</td>
                            <td>{{item.releaseDate}}</td>
                            <td>{{item.price | currency:'CAN':true: '1.2-2'}}</td>
                            <td>{{item.starRating}}</td>
                        </tr>

                    </tbody>
                </table>
            </div>
    </div>
</div>

Solution

  • Change this line

    <table class = 'table' *ngIf='products && products.length | productFilter:listFilter'> // wrong
    

    to this

    <table class='table' *ngIf='products && products.length'> // correct

    Change this line

    <tr *ngFor='let item of products'>
    to this
    <tr *ngFor='let item of products | productFilter:listFilter'> // applying pipe here

    Hope that helps.