【问题标题】:Upgrade to angular 9 Subject now caused ExpressionChangedAfterItHasBeenCheckedError升级到 Angular 9 主题现在导致 ExpressionChangedAfterItHasBeenCheckedError
【发布时间】:2020-02-11 06:49:46
【问题描述】:

升级到 Angular 版本 9 后,我收到一系列错误:“ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value for 'hidden': 'true'. Current value: 'false'.”。

这是由我的 OverlayService 和 App-Component 之间的交互引起的。当我使用该服务更改 overlayOff 变量的值时,我的覆盖将启动。我得到错误。

这不是 8.x 版中的行为。每次从服务器更改 DOM 时,我都会在项目中频繁关闭和打开覆盖。有关如何解决此问题的建议。

app.component.html

<div class="container-fluid">
  <div [hidden]="overlayOff" id="overlay">
    <mp-loading marginTop="25"></mp-loading>
  </div>     
  <router-outlet></router-outlet>
</div>

app.component.ts

    @Component({
    // tslint:disable-next-line:component-selector
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {

     private overlaySubscription: Subscription;
       overlayOff = true;

     constructor({
       private overlayService: OverlayService) 
     }

     ngOnInit() {
       this.overlaySubscription =      this.overlayService.toggleOverlay
        .subscribe(nextValue => {
           this.overlayOff = (nextValue === undefined) ?  !this.overlayOff : nextValue;
    // console.log('OverlayOff:' + this.overlayOff);
          });
   }

      ngOnDestroy() {
        this.overlaySubscription.unsubscribe();
      }

     }

overlay.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

 @Injectable({
   providedIn: 'root'
  })
 export class OverlayService {
    toggleOverlay: Subject<boolean> = new Subject();
    constructor() { }

    overlayOn() {
       // console.log('overlay On');
     this.toggleOverlay.next(false);
    }
    overlayOff() {
       this.toggleOverlay.next(true);
     }
   }

【问题讨论】:

  • 从 Angular 7 开始,我就一直在忍受这个错误。
  • 我还是会花一些时间来理解错误,在模板中进行更改检测和顺序检查的单向数据流顺序。虽然恼人的错误教会了我很多东西。我见过的更有趣的修复之一是用 &lt;div *ngIf=“true”&gt;&lt;div&gt; 包装麻烦的元素(在这种情况下不适用)
  • 我计划向 Andrew 咨询,但如果有人有其他研究材料,我会全力以赴。我认为这可行的唯一原因是我在检查后更新了变量,从而减轻了原始问题。由于更新发生在之后,没有错误。
  • 在我的情况下,解决方案是将逻辑从 ngInit 移动到 cunstruct。它解决了我的问题,但它不能在所有情况下都有帮助。

标签: angular


【解决方案1】:

你最好使用async 管道。这样你就完全不用订阅了

<div class="container-fluid">
  <div [hidden]="overlayOff$ | async" id="overlay">
    <mp-loading marginTop="25"></mp-loading>
  </div>     
  <router-outlet></router-outlet>
</div>

component.ts:

readonly overlayOff$ = this.overlayService.toggleOverlay.pipe(
  pairwise(),
  map(([prev, next]) => next == null ?  !prev : next),
  startWith(true)
);

还建议使用 changeDetectionStrategy OnPush。这是为了防止错误检测可能发现不需要的更改

【讨论】:

  • 对我不起作用。在 tweeking 之后,它只工作了一次
【解决方案2】:

虽然我不知道为什么会出现问题,但似乎对我有用的解决方案如下。

首先在 app.component.ts 中添加 AfterContentChecked 生命周期钩子。

创建一个新的私有变量overlayResponseHolder

下一次更改订阅

.subscribe(nextValue => {
    this.overlayResponseHolder = nextValue;
  });

创建一个新函数 ngAfterContentChecked

ngAfterContentChecked() {
  this.overlayOff = this.overlayResponseHolder;
}

不确定这是一个解决方案还是一个 kluge,但现在它又可以工作了。

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 2019-10-04
    • 2020-05-16
    • 2020-10-16
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多