导致' ...的Angular2管道在检查后发生了变化。开发错误

时间:2016-04-23 14:14:11

标签: typescript angular

我知道为什么会抛出此错误,但我不了解如何组织我的代码来修复它。这是问题

@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
}

这真的是最好/唯一的方式吗?感觉就像我自己处理变化检测的某些方面一样!

1 个答案:

答案 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检查阵列中的项目是否已添加或删除或替换。 这仍然不包括数组中包含的项目的属性更改。