【问题标题】:Expression has changed after it was checked - Event subscription updates检查后表达式已更改 - 事件订阅更新
【发布时间】:2020-07-13 01:45:52
【问题描述】:

虽然我知道ERROR 发生的原因,但是,我想知道如何在以下情况下克服:

我在app.component 中有一个通用加载器。对于某些子路由,它将在ngOnInit 生命周期中更新加载器值,直到获取记录。另外,我不想使用resolver,因为我正在解析组件中的查询参数,然后传递给服务以获取记录。

ERROR是由于加载器的默认值为false,在子组件生命周期ngOnInit钩子期间变为true

请看下面的sn-p:

// app.component.ts
 viewModel = {
    showLoader: false
};
ngOnInit() {
    this.eventService.on(ApplicationEvents.SHOW_FULL_PAGE_LOADER, (value) => {
        this.viewModel.showLoader = value;
    });
}
// app.component.html
<div class="full-page-loader" *ngIf="viewModel.showLoader"><em class="fa fa-cog fa-spin loader-icon"></em></div>

以下是来自延迟加载子组件的 sn-p:

ngOnInit() {
    this.loadData();
    this.cart = this.cartService.getCart();
  }

private loadData() {
this.eventService.showFullPageLoader(); // <-- This will emit an event to show the loader 
this.umrahDataService.getServices(UmrahServiceType.Visa).then((resp) => {
  this.visas = resp.map((v) => {
    v.image = '/assets/img/umrah/visa-processing.jpg';
    return v;
  });

  this.eventService.hideFullPageLoader();
  this.actionInProcess = false;
}).catch((er) => {
  this.alertService.alert('SERVER_ERROR');
  this.eventService.hideFullPageLoader();
  this.actionInProcess = false;
});
}

错误错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。以前的值:'ngIf: false'。当前值:'ngIf: true'。 在 viewDebugError (core.js:19629) 在表达式ChangedAfterItHasBeenCheckedError (core.js:19617) 在 checkBindingNoChanges (core.js:19833) 在 checkNoChangesNodeInline (core.js:29533) 在 checkNoChangesNode (core.js:29522) 在 debugCheckNoChangesNode (core.js:30126) 在 debugCheckDirectivesFn (core.js:30054) 在 Object.eval [as updateDirectives] (AppComponent.html:3) 在 Object.debugUpdateDirectives [as updateDirectives] (core.js:30043) 在 checkNoChangesView (core.js:29421)

虽然我也尝试了 BehaviorSubjectasync 管道,但这也无济于事。 期待反馈。 谢谢

【问题讨论】:

  • 确切的异常消息是什么?
  • @AshokanSivapragasam 更新了问题。请检查。

标签: angular angular-lifecycle-hooks


【解决方案1】:

在大多数情况下,将您的响应式代码移至 ngAfterViewInit 会有所帮助。所以在你的子组件中而不是:

ngOnInit() {
    this.loadData();
    this.cart = this.cartService.getCart();
}

使用

ngAfterViewInit() {
    this.loadData();
    this.cart = this.cartService.getCart();
}

您也可以在您的app.component.ts 中使用setTimeout,但这更像是一种技巧,而不是一种解决方案。

【讨论】:

  • 寻找解决方案而不是黑客攻击!
  • @Cleancode 使用 setTimeout 是一个 hack,而 ngAfterViewInit 是一个相当干净的解决方案 IMO。
  • 好吧,ngOnInit 生命周期需要做一些事情,由于具体问题,不应该推送afterViewInit。这是一个黑客兄弟!
【解决方案2】:

每当您在视图加载后更改数据时,让 Angular 观察者消化这些更改。 Angular 有 ChangeDetectorRef 服务。您可以注入此服务并强制角度检测并包含摘要周期中的更改。

import { Component, ChangeDetectorRef  } from '@angular/core';

@Component({
  selector: 'app-your-comp',
  templateUrl: 'your-comp.component.html',
  styleUrls: ['your-comp.component.scss']
})
export class YourCompPage {
    constructor(private changeDetectorRef: ChangeDetectorRef) {}

    ngAfterViewInit() {
        ..any data changes or your flag in this case..
        this.changeDetectorRef.detectChanges();
        // -- OR --
        this.eventSubscription.someEvent(() => {
            ..any data changes or your flag in this case..
            this.changeDetectorRef.detectChanges();
        });
    }
}

附: https://indepth.dev/everything-you-need-to-know-about-the-expressionchangedafterithasbeencheckederror-error/

【讨论】:

  • 感谢您的回答,不过,我也尝试过手动运行CDthis.cd.detectChanges(); 但没用。
  • 根据这篇文章和 Yuriy,最好在 ngAfterViewInit() 和 change-detector 中进行消化。 indepth.dev/…
  • 不。 ngAfterView 抛出了同样的错误,但是我添加了一个隐藏类,而是从 DOM 中删除 div。虽然我仍然期待实际的解决方案。
【解决方案3】:

Angular 变更检测进程是同步的,为了避免这个错误,我们可以将其设为异步进程,并且我们可以通过执行类似的操作使该代码在变更检测之外运行。

ngOnInit(){
  this.ngZone.runOutsideAngular(() => {    
     this.interval = window.setInterval(() => {
      this.eventService.on(ApplicationEvents.SHOW_FULL_PAGE_LOADER, (value) => {
      this.viewModel.showLoader = value;
      });
  }, 1)});
};

【讨论】:

    猜你喜欢
    • 2017-01-24
    • 1970-01-01
    • 2017-06-08
    • 2017-09-16
    • 1970-01-01
    • 2016-10-19
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多