Angular 4:`ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后发生了变化

时间:2017-05-19 12:56:13

标签: angular typescript eventemitter

我的子模块中的每个EventEmiiter都会出现此错误,但我无法找到解决方法。

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'.

这是触发我的EventEmitter的原因:

ngOnChanges(changes: any) {
    if (changes.groupingTabValid) {
        if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
            this.groupingTabValidChange.emit(this.groupingTabValid);
        }
    }
}

这是我的“主要”组件的HTML

<year-overview-grouping [definitionDetails]="definitionDetails"
                        [fixedData]="fixedData"
                        [showValidation]="showValidation"
                        [groupingTabValid]="groupingTabValid"
                        (groupingTabValidChange)="setValidators('groupingTab', $event)">

</year-overview-grouping>

调用此功能

public setValidators(validator: string, e: boolean) {
    switch (validator) {
        case "groupingTab":             
            this.groupingTabValid = e;
            break;

        case "selectionTab":
            this.selectionTabValid = e;
            break;
    }

    if (this.groupingTabValid && this.selectionTabValid) {
        this.valid = true;
    } else {
        this.valid = false;
    }
}

1)在一个简单的解释中,是什么导致了这个错误?

2)我可以采取哪些措施来解决这个问题?

5 个答案:

答案 0 :(得分:11)

遵守单向数据流规则

尝试使用setTimeout

推迟对一个tick的调用
if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
    setTimeout(() => this.groupingTabValidChange.emit(this.groupingTabValid), 0)
}

答案 1 :(得分:4)

只需导入ChangeDetectionStrategy,然后将其添加到您的组件

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: 'app-bla-bla-bla',
  templateUrl: './xxxxx'
})

答案 2 :(得分:2)

您可以避免使用setTimeout并告诉Angular在初步检查后即将发生更改。

您可以将ChangeDetectorRef注入您的组件并使用其markForCheck方法。

/* ... */

constructor(private cdr: ChangeDetectorRef) {}

/* ... */

if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue {
  this.cdr.markForCheck();
  this.groupingTabValidChange.emit(this.groupingTabValid);
}

答案 3 :(得分:1)

我自己刚开始看这个异常类型,所以没有专家,但是假设它是在那里停止反馈循环。

我看不出任何明显的原因,你想要将值发送给孩子并备份到父,但假设孩子应用了一些额外的逻辑。 对我来说,在服务而不是子组件中应用任何其他逻辑似乎更好。

我意识到plunker代码没有循环,但Angular机制似乎相当简单 - 只需在循环结束时重新检查值。请注意,您的问题代码中的 groupingTabValid 会直接反馈。

查看给定的plunker代码,从结构上来说,可以在父级上处理对年龄的更改。 click事件将为(click)=changeAge(age.value),并且方法(在父级上)可以处理它

changeAge(inputAge) {
  this.newAge = inputAge;
  this.person.age = inputAge;
}

这是一个掠夺者的叉子。 Modified plunker
子组件仍然更新person.age,但不再导致错误,因为该值与父项上设置的值相同。

答案 4 :(得分:-3)

我有同样的问题。为了解决这个问题,我做了这个小小的黑客攻击。

setTimeout((()=>this.valueSelect.emit(idChange)), 0);

其中“this.valueSelect.emit(idChange)”是我将发出的变化