Am looping over an array of object in my view like this (without the pipe I get the whole list displayed):
<ion-list>
<ion-item *ngFor= "let category of (productCategories | onlyhomecategory) " >
<ion-icon name="arrow-forward" item-right></ion-icon>
{{category.title}}
</ion-item>
</ion-list>
I am feeding the array into a custom pipe called onlyhomecategory
to filter out any categories that don't have a home
property like this:
import {Injectable, Pipe} from '@angular/core';
@Pipe({
name: 'onlyhomecategory'
})
@Injectable()
export class OnlyHomeCategories {
transform(productCategories: any[] , args: any[]) {
console.log(productCategories.length); //retuns 0
//If I hard-code/mock the array, pipe works as expected.
return productCategories.filter(category => category.home);
}
}
This is the shape of how the array looks like:
[
{
home: 1,
title: "Greevy Swaney",
text: "Find the right area",
},
{
home: 2,
title: "Taney Wearx",
text: "Choose the right system",
},
{
title: "Tine rider",
},
{
title: "Shade",
}
];
This is the service:
import {Injectable} from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';
@Injectable()
export class ProductCategories {
data: any = null;
constructor(public http: Http) {}
load() {
if (this.data) {
// already loaded data
return Promise.resolve(this.data);
}
// don't have the data yet
return new Promise(resolve => {
this.http.get('https://xxxxxxxxxxxxxxxxxxxxxxxx')
.map(res => res.json())
.subscribe(data => {
this.data = data;
resolve(this.data);
});
});
}
}
This is the view component:
import {Page, NavController} from 'ionic-angular';
import {Inject} from '@angular/core'
import {ProductCategories} from '../../providers/product-categories/product-categories'
import {OnlyHomeCategories} from '../../pipes/only-home-categories'
@Page({
templateUrl: 'build/pages/product-category/product-category.html',
pipes: [OnlyHomeCategories]
})
export class ProductCategoryPage {
public productCategories = [];
constructor(public nav: NavController, private prodCat: ProductCategories) {
this.prodCat.load()
.then(data => {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this.productCategories.push(data[key]);
}
}
console.log(`this.productCategories.length: ${this.productCategories.length}`); // this return correct length
});
} }
Am not sure where am going wrong. Without the custom pipe, my view shows all the categories but I can't seem to get the pipe to work.
Angular doesn't monitor array content changes. Because you initialize productCategories with an empty array and later add elements to this same array, change detection doesn't detect the change and doesn't invoke the pipe again.
pure: false
You can make the pipe impure, so it gets called every time change detection runs, not only when the pipe input changes
@Pipe({
name: 'onlyhomecategory',
pure: false
})
export class OnlyHomeCategories {
transform(productCategories: any[] , args: any[]) {
console.log(productCategories.length); //retuns 0
return productCategories.filter(category => category.home);
}
}
disadvantages:
Making a pipe impure has performance implications, because the pipe is called a lot (every time Angular runs change detection). To not cause this too much harm, ensure that the pipe doesn't do expensive work. For example try to cache the result of expensive calculations as long as the relevant inputs haven't changed. You need to keep track of previous and new values yourself.
different object
You can also make Angular detect the change, by not only adding content but creating a new - different - array.
this.prodCat.load()
.then(data => {
let arr = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
arr.push(data[key]);
}
}
this.productCategories = arr;
console.log(`this.productCategories.length: ${this.productCategories.length}`); // this return correct length
});
disadvantages:
If the array is large, copying can be expensive.
Hint
If you modify an array that already contains values you can create a copy using slice()
:
this.prodCat.load()
.then(data => {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this.productCategories.push(data[key]);
}
}
this.productCategories = this.productCategories.slice();
console.log(`this.productCategories.length: ${this.productCategories.length}`); // this return correct length
});
Plunker example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With