I understand the reason for this error being thrown, but I am struggling with organizing my code to resolve it. Here is the problem:
@Component({
selector: 'article',
templateUrl: 'article.html',
moduleId: module.id,
directives: [Toolbar]
})
export class Article {
public toolbar: Array<IToolbarItem>;
constructor() {
this.toolbar = [
{
css: 'ic-save',
action: (item) => { },
visible: false
},
<IDropdownItem>{
css: 'ic-edit',
items: [
{
css: 'ic-edit',
label: 'Edit Article',
action: (item) => { }
},
{
css: 'ic-edit',
label: 'Edit Content',
action: (item) => {
this.toolbar[0].visible = true;
}
}
]
}
];
}
}
and here is the toolbar component along with its template:
@Component({
selector: 'toolbar',
moduleId: module.id,
templateUrl: 'toolbar.html',
styleUrls: ['toolbar.css'],
pipes: [VisiblePipe],
encapsulation: ViewEncapsulation.None
})
export class Toolbar {
@Input() items: Array<IToolbarItem>;
}
<div class="container">
<div class="toolbar">
<div class="toolbar-item" *ngFor="#i of (items | visible)">
.
.
.
Lastly, let's take a look at the VisiblePipe
pipe:
@Pipe({
name: 'visible',
pure: false
})
export class VisiblePipe implements PipeTransform {
transform(value) {
return (<Array<any>>value).filter(v => v.visible !== false);
}
}
The article component uses the toolbar component to which the toolbar array is passed, and then the visible pipe filters out items with the visible property set to false.
An error occurs when the VisiblePipe
pipe runs. It seems like the pipe transform code is executing after the change detection process. Why could that be?
Edit
Following Gunter's suggestion, I have made updates to my VisiblePipe
pipe and now it's functioning correctly:
export class VisiblePipe implements PipeTransform {
private previousValue: Array<IVisibleItem>;
private cacheResult: Array<IVisibleItem>;
transform(value: Array<IVisibleItem>) {
if (!this.previousValue || !compareArrays(this.previousValue, value)) {
this.previousValue = value.map(i => { return { visible: i.visible } });
this.cacheResult = value.filter(v => v.visible !== false);
}
return this.cacheResult;
}
}
function compareArrays(arrayOne: Array<IVisibleItem>, arrayTwo: Array<IVisibleItem>) {
if (arrayOne.length !== arrayTwo.length) {
return false;
}
for (let i = 0, l = arrayOne.length; i < l; i++) {
let arrayOneEntry = arrayOne[i];
let arrayTwoEntry = arrayTwo[i];
if (arrayOneEntry.visible !== undefined &&
arrayTwoEntry.visible !== undefined &&
arrayOneEntry.visible !== arrayTwoEntry.visible) {
return false;
}
}
return true;
}
interface IVisibleItem {
visible: boolean
}
Is this truly the best or only way? It feels like I'm taking control of some part of the change detection process myself!