usmanwalana usmanwalana - 2 months ago 24
TypeScript Question

Angular 2 Pipe - Cannot read property 'toString' of undefined

I have a search pipe setup in angular 2 . The search pipe was working perfectly when i was on angular beta 14, now i upgraded to rc5 and the search pipe is broken and i get error. If i remove the pipe from the html code the products load. It is a generic search and filter pipe and should be used in many modules. Please help to resolve the issue.

TypeError: Cannot read property 'toString' of undefined
at SearchPipe.compareWithAllFields (http://localhost:4200/main.bundle.js:72117:57)
at Array.filter (native)
at SearchPipe.transform


search.pipe.ts

import { Pipe, PipeTransform } from '@angular/core';
import {isObject} from "rxjs/util/isObject";
import {isEmpty} from "rxjs/operator/isEmpty";
import {empty} from "rxjs/Observer";
@Pipe({
name: 'search'
})
export class SearchPipe implements PipeTransform
{
transform(input, [searchString]:Array<String>)
{
if (input == null) return input;
return input.filter(this.compareWithAllFields, searchString);
}

compareWithAllFields(value, index)
{
var fields = Object.keys(value);
for (let i = 0; i < fields.length; i++)
{
if (value[fields[i]] != null)
{
if (isObject(value[fields[i]]))
{
var childFields = Object.keys(value[fields[i]]);
if (childFields.length > 0)
{
for (let j = 0; j < childFields.length; j++)
{
if ((value[fields[i]][childFields[j]] + "").indexOf(this.toString()) !== -1)
{
return true;
}
}
}
}
if ((value[fields[i]] + "").indexOf(this.toString()) !== -1)
{
return true;
}
}
}
return false;
}
}


list-products.component.html

<div class="container">
<div class="row">
<div class="col-sm-3 form-group">
<input placeholder="search product" class="form-control" type="text" #searchProduct (keyup)="0">
</div>
<div class="col-sm-3 col-sm-offset-6">
<button [routerLink]="['/LoggedIn','Product','ProductAdd']" class="btn btn-lg btn-app">Add Product</button>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<h3>Products</h3>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Sr #</th>
<th>Name</th>
<th>Category</th>
<th>Barcode</th>
<th>Unit</th>
<th>Description</th>
<th>Quantity</th>
<th>Minimum Stock Level</th>
<th>Discount</th>
<th>Cost</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let product of products | search:searchProduct.value;let serial = index">
<td>{{ serial+1 }}</td>
<td>{{ product.name}}</td>
<td>{{ product.productCategory.name}}</td>
<td>{{ product.barcode}}</td>
<td>{{ product.unit?.name}}</td>
<td>{{ product.description}}</td>
<td>{{ product.quantity}}</td>
<td>{{ product.minimumStockLevel}}</td>
<td>{{ product.discount}}</td>
<td>{{ product.cost}}</td>
<td>
<button class="btn btn-danger" (click)="delete(product)">Delete</button>
<button class="btn btn-default"
[routerLink]="['/LoggedIn','Product','ProductEdit',{id:product.id}]">Edit
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

Answer

@usmanwalana, the PIPE API has changed since RC3/4, it now returns the 2nd parameter as a string rather than an array.

So change,

transform(input, [searchString]:Array<String>)

to

transform(input, searchString)