Angular-Material报错Previous value: 'ngIf: undefined'. Current value: 'ngIf: false

445 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。 也是一个以前遇到过的问题,由于偷懒+不影响项目进行就没有理会,今天找到了解决方法。

浏览器报错

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: undefined'. Current value: 'ngIf: false'.
    at viewDebugError (core.js:22944:1)
    at expressionChangedAfterItHasBeenCheckedError (core.js:22932:1)
    at checkBindingNoChanges (core.js:23142:1)
    at checkNoChangesNodeInline (core.js:31436:1)
    at checkNoChangesNode (core.js:31425:1)
    at debugCheckNoChangesNode (core.js:32022:1)
    at debugCheckDirectivesFn (core.js:31954:1)
    at Object.updateDirectives (supplier-order-warehouse.component.html:146:1)
    at Object.debugUpdateDirectives [as updateDirectives] (core.js:31947:1)
    at checkNoChangesView (core.js:31324:1)

简单来说就是isLoading是布尔类型,但值却是undefined,(可能好心的)帮你重置成了false

isLoading的用法

用于加载进度条
isLoading=true时,进度条显示,当isLoading=false时,进度条隐藏
进度条加载期间无法进行网页操作,所以也可以作为简易防抖使用

<div *ngIf="isLoading" class="loading">
    <mat-spinner></mat-spinner>
</div>

例如表格加载的代码为:

// 更新表格:
  fetchTableInfo(): void {
    //进度条加载
    this.isLoading = true;
    let searchParamsStr = '';

    if (isNotNullOrUndefined(this.searchForm.value.transports_number)) {
      searchParamsStr += '&transports_number=' + this.searchForm.value.transports_number;
    }

    this.purchaseService.getSupplierWarehouseList(this.paginator.pageIndex, searchParamsStr).subscribe(
      res => {
        this.tableData = res['data'].data || [];
        this.tableDataLength = res['data'].count;
      },
      e => console.log(e),
      () => this.isLoading = false //API调用结束后进度条隐藏
    );
  }

当出现这个问题的时候,我发现我的表格页面和详情页面关于isLoading的定义一模一样,表格页面却会出错
最近生命周期理解有所进步,一下就发现了问题出现的原因,极其简单:
由于详情页面需要提前渲染,所以获取信息放在了ngOnInit中,fetchTableInfo()函数加载的时候首先就会定义isLoading=true
而表格获取需要等一些元素先加载完成,放在了ngAfterViewInit中,由于isLoading: boolean;的定义并没有赋值,浏览器已经读取了isLoading的值,这时候轮到ngAfterViewInit加载,isLoading的赋值就无效了。

解决办法

  • isLoading放在ngOnInit中时,ngOnInit中的某个函数给isLoading赋值即可
  • isLoading放在ngAfterViewInit中时,将isLoading: boolean;修改为isLoading = true;