【问题标题】:Error:Expression has changed after it was checked - in constructor错误:检查后表达式已更改 - 在构造函数中
【发布时间】:2020-08-13 11:30:45
【问题描述】:

这是在我的 html 文件中:

  <div id="my-div" [ngClass]="hasSetting ? 'my-container' : 'opacity-div my-container'">    
    <dx-load-panel
      #loadPanel
      [(visible)]="!hasSetting" >
    </dx-load-panel>
  </div>

这是我的组件:

export class TurnoverWidgetComponent {

  departments: DropdownOption[] = [];
  hasSetting: boolean;

  constructor(
    private myService: MyService
  ) {

    forkJoin(
      this.myService.hasSetting(),
      this.myService.getDepartments()
    ).subscribe(
      ([hasSetting, departments]) => {
        this.hasSetting = hasSetting;

          this.departments = departments.map(item => {
            return {
              id: item.id,
              name: item.name
            }
          });
      }
    );
  }
}

我得到错误错误:在检查后表达式已更改 - 在构造函数中,从真到假,反之亦然。根据我的研究,此错误发生在组件初始化后发生的事件中,但是我没有此类事件,我的更改发生在构造函数中。我试着把它放在 oninit 事件中,同样的事情发生了。

【问题讨论】:

  • 像hasSetting这样初始化是否还有错误:boolean = false; ?
  • 是的,我有。
  • 您使用 ngAfterViewInit 挂钩是否有原因?在这种情况下,更合适的是 ngOnInit。只需更换挂钩,您的问题就会得到解决
  • @Andrei 但是我根本没有使用 ngAfterViewInit,你在哪里看到我在使用它?

标签: angular angular10


【解决方案1】:

我认为您应该在设置超时下提供您的逻辑。这将解决您的问题。

ngAfterViewInit() {
     forkJoin(
      this.myService.hasSetting(),
      this.myService.getDepartments()
    ).subscribe(
      ([hasSetting, departments]) => {
        
    setTimeout(() => {
       this.hasSetting = hasSetting;
    },200);
          this.departments = departments.map(item => {
            return {
              id: item.id,
              name: item.name
            }
          });
      }
    );

【讨论】:

  • 这不起作用。我也不喜欢使用随机的 setTimeouts。
【解决方案2】:

当组件已经检查更新并想要更新视觉效果时,会发生这种情况,并且在更新之前再次检查并发现数据不一样... 很烦人。

但是你可以稍微改变你的策略来摆脱它(我希望。我没有测试它)

你不需要订阅你的数据,让异步管道来做,因为它会同时使用数据,当你改变到另一个路由时也会取消订阅, 只需使用运算符以您喜欢的方式塑造数据并将其提供给 html。

  data$: Observable<{hasSetting: boolean; departments: DropdownOption[] }>
  constructor(
    private myService: MyService
  ) {

    this.data$ = forkJoin(
      this.myService.hasSetting(),
      this.myService.getDepartments()
    ).pipe(map(x=>{
      return {
        hasSetting: x[0],
        departments: x[1]
      }
    }))
  }
  <div *ngIf="data$ | async as data" [ngClass]="data.hasSetting ? 'my-container' : 'opacity-div my-container'">    
    <dx-load-panel
      #loadPanel
      [visible]="!hasSetting" >
    </dx-load-panel>
  </div>

【讨论】:

    【解决方案3】:

    您需要了解,当我们从它得到答案时,我们将进行 http 调用并更改组件变量。在开发模式下,Angular 会调用两次更改检测来检查值是否未更改,以确保代码不会出现意外行为。这里 angular 抱怨在它第一次检查组件值之后值已经改变了。

    这里是更新的代码,以确保 Angular 在我们在 http 回调中更改后检测到更改:

        export class TurnoverWidgetComponent implementes OnInit {
        
          departments: DropdownOption[] = [];
          hasSetting: boolean;
        
          constructor(
            private myService: MyService,
            private cd: ChangeDetectorRef,
          ) {}
    
          ngOnInit() {
    
            forkJoin(
              this.myService.hasSetting(),
              this.myService.getDepartments()
            ).subscribe(
              ([hasSetting, departments]) => {
                this.hasSetting = hasSetting;
        
                  this.departments = departments.map(item => {
                    return {
                      id: item.id,
                      name: item.name
                    }
                  });
                this.cd.detectChanges(); // this will tell angular that we changed something and explicitly invoke change detection.
              }
            );
         }
        }
    

    【讨论】:

      猜你喜欢
      • 2019-05-14
      • 2018-05-10
      • 2018-05-11
      • 2017-06-23
      • 2020-06-29
      • 2019-01-13
      • 2017-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多