我的组件具有依赖于当前日期时间的样式。在我的组件中,我有如下函数。

  private fontColor( dto : Dto ) : string {
    // date d'exécution du dto
    let dtoDate : Date = new Date( dto.LastExecution );

    (...)

    let color =  "hsl( " + hue + ", 80%, " + (maxLigness - lightnessAmp) + "%)";

    return color;
  }

lightnessAmp从当前datetime开始计算。如果dtoDate在过去24小时内,则颜色会发生变化。

准确的错误如下:

表达式在检查后发生了变化。先前值:'hsl(123, 80%, 49%)'。当前值:'hsl(123, 80%, 48%)'

我知道异常只出现在开发模式的值被检查的时刻。如果检查值与更新值不同,则抛出异常。

因此,我尝试在以下钩子方法中更新每个生命周期的当前datetime,以防止异常:

  ngAfterViewChecked()
  {
    console.log( "! changement de la date du composant !" );
    this.dateNow = new Date();
  }

...但是没有成功。


当前回答

将代码从ngAfterViewInit移到ngAfterContentInit。

视图在内容之后被初始化,因此ngAfterViewInit()在ngAfterContentInit()之后被调用

其他回答

我认为你能想到的最好和最干净的解决方案是:

@Component( {
  selector: 'app-my-component',
  template: `<p>{{ myData?.anyfield }}</p>`,
  styles: [ '' ]
} )
export class MyComponent implements OnInit {
  private myData;

  constructor( private myService: MyService ) { }

  ngOnInit( ) {
    /* 
      async .. await 
      clears the ExpressionChangedAfterItHasBeenCheckedError exception.
    */
    this.myService.myObservable.subscribe(
      async (data) => { this.myData = await data }
    );
  }
}

用Angular 5.2.9测试过

在更改之后显式地运行更改检测:

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

constructor(private cdRef:ChangeDetectorRef) {}

ngAfterViewChecked()
{
  console.log( "! changement de la date du composant !" );
  this.dateNow = new Date();
  this.cdRef.detectChanges();
}

博士TL;

ngAfterViewInit() {
    setTimeout(() => {
        this.dateNow = new Date();
    });
}

虽然这是一种变通方法,但有时真的很难以更好的方式解决这个问题,所以如果您使用这种方法,请不要责怪自己。没关系。

示例:初始问题[链接],用setTimeout()解决[链接]


如何避免

一般来说,这个错误通常发生在你添加ngAfterViewInit之后(甚至在父/子组件中)。第一个问题是问你自己,我能没有ngAfterViewInit吗?也许你把代码移到某个地方(ngAfterViewChecked可能是另一种选择)。

例如:[链接]


ngAfterViewInit中影响DOM的async也可能导致这个。也可以通过setTimeout或在管道中添加delay(0)操作符来解决:

ngAfterViewInit() {
  this.foo$
    .pipe(delay(0)) //"delay" here is an alternative to setTimeout()
    .subscribe();
}

例如:[链接]


好的阅读

关于如何调试以及为什么会发生这种情况的好文章:链接

以前所有的解决方案都不适合我,这是唯一一个真正管用的。

错误信息示例:

AppComponent.html:1错误 ExpressionChangedAfterItHasBeenCheckedError:表达式已经改变 在检查之后。之前的值:'ngIf: true'。当前值: “ngIf:假”。 在viewDebugError (core.js:20440) 在expressionChangedAfterItHasBeenCheckedError (core.js:20428) ...

解决方案 在触发问题的组件中导入ChangeDetectorRef, AfterContentChecked 然后加上:

 ngAfterContentChecked(): void {
    this.changeDetector.detectChanges();
  }

例子

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

import { Title } from '@angular/platform-browser';

import { environment } from '@env/environment';
import { LayoutService } from '@app/core/layout/layout.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: []
})
export class AppComponent implements OnInit, AfterContentChecked {
  env = environment;
  title = this.env.appName;
  partials: any = {};

  public constructor(
    private titleService: Title,
    public layout: LayoutService,
    private changeDetector: ChangeDetectorRef,
  ) {}

   ngOnInit() {
    this.titleService.setTitle(this.env.appName);
    
    this.layout.getLayout().subscribe(partials => {
      this.partials = partials;
    });
  }

  ngAfterContentChecked(): void {
    this.changeDetector.detectChanges();
  }
}

不是我的:这是来源 https://gist.github.com/vades/a225170304f34f88a7a5d48bf4b1f58c

一个小工作周围我用过很多次

Promise.resolve(data).then(() => { console.log (" !更改组件日期!”); this。dateNow = new Date(); this.cdRef.detectChanges (); });