我知道为什么会抛出此错误,但我不了解如何组织我的代码来修复它。这是问题
@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;
}
}
]
}
];
}
}
以及工具栏组件和模板
@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)">
.
.
.
最后是VisiblePipe
管道
@Pipe({
name: 'visible',
pure: false
})
export class VisiblePipe implements PipeTransform {
transform(value) {
return (<Array<any>>value).filter(v => v.visible !== false);
}
}
因此,文章组件使用工具栏数组传递到的工具栏组件,然后使用可见管道过滤掉visible属性设置为false的项目。
运行VisiblePipe
管道时,将引发错误。因此,出于某种原因,管道转换代码在更改检测后运行?为什么呢?
修改
所以我根据Gunter的建议更新了我的VisiblePipe
管道,并且它正在运行
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
}
这真的是最好/唯一的方式吗?感觉就像我自己处理变化检测的某些方面一样!
答案 0 :(得分:3)
导致错误,因为在devMode
每次转弯时Angular运行更改检测两次,并且即使输入值没有更改,管道也会为两个后续调用返回不同的数组实例。
当设置为pure: false
时,甚至不允许这样做。
要修复它,请确保管道在输入未更改时为后续调用返回相同的数组实例。
@Pipe({
name: 'visible',
pure: false
})
export class VisiblePipe implements PipeTransform {
cached:any;
transform(value) {
if(value == this.cached && this.resultCached) {
return this.resultCached;
}
this.value = value;
this.resultCached = (<Array<any>>value).filter(v => v.visible !== false);
return this.resultCached;
}
}
如果可以从外部修改阵列(不创建新实例),那么您也需要处理这个问题。然后,您需要检查自上次调用以来数组的内容是否已更改。
您可以使用IterableDiffers检查阵列中的项目是否已添加或删除或替换。 这仍然不包括数组中包含的项目的属性更改。