typescript Angular 4:`ExpressionChangedAfterItHasBeenCheckedError:检查后表达式已更改

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44070732/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 04:33:47  来源:igfitidea点击:

Angular 4: `ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked

angulartypescripteventemitter

提问by Nicolas

Every EventEmiiter in my child module gives this error and I can't find a fix for this.

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

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

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

This is what triggers my EventEmitter:

这就是触发我的 EventEmitter 的原因:

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

Here is my "main" componenent's HTML

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

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

</year-overview-grouping>

Which calls this function

哪个调用这个函数

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) In a a simple explanation, what's causing this error?

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

2) What steps can I take to solve this?

2)我可以采取什么步骤来解决这个问题?

回答by Draeken

Abide by the unidirectional data flow rule

遵守单向数据流规则

Try to postpone the call to emit for one tick with a setTimeout

尝试使用 setTimeout 推迟发出一个滴答声的调用

if (changes.groupingTabValid.currentValue !== changes.groupingTabValid.previousValue) {
    setTimeout(() => this.groupingTabValidChange.emit(this.groupingTabValid), 0)
}

回答by Cengkuru Michael

Just import ChangeDetectionStrategy and then add this to your component

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

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

回答by Micha? Pietraszko

You can avoid using setTimeoutand tell Angular that changes are about to happen after initial check.

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

You can inject ChangeDetectorRefinto your component and use its markForCheckmethod.

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

/* ... */

constructor(private cdr: ChangeDetectorRef) {}

/* ... */

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

回答by Richard Matsen

I'm just starting to look at this exception type myself, so no expert, but presume that it's there to stop feedback loops.

我刚刚开始自己​​研究这种异常类型,所以不是专家,但假设它可以停止反馈循环。

I can't see any obvious reason why you want to send the value down to the child and back up to the parent, but presume the child applies some additional logic. To me, seems better to apply any additional logic in a service rather than a child component.

我看不出任何明显的原因,为什么您要将值向下发送给子级并返回给父级,但假设子级应用了一些额外的逻辑。对我来说,在服务而不是子组件中应用任何附加逻辑似乎更好。

I realize the plunker code doesn't have a loop, but the Angular mechanism seems rather simple - just re-checks values at the end of the cycle. Note, groupingTabValidin your question code does feedback directly.

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

Looking at the plunker code as given, structurally the change to age can be handled on the parent. The click event would be (click)=changeAge(age.value)and the method (on parent) to handle it

查看给定的 plunker 代码,结构上可以在父级上处理年龄的更改。单击事件将是(click)=changeAge(age.value)处理它的方法(在父级上)

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

Here's a fork of the plunker. Modified plunker
The child component still updates person.age, but no longer causes an error as the value is the same as set on the parent.

这是plunker的一个叉子。修改plunker
子组件仍然更新person.age,但不再报错,因为值与父组件设置的相同。