首页 > 解决方案 > 将值传递给组件时的 ExpressionChangedAfterItHasBeenCheckedError

问题描述

在将值作为输入传递给自定义子组件时,我总是得到表达式在检查后发生更改的错误。子组件如下所示:

<mat-card *ngIf="user$ | async as user">
    <div *ngIf="!editMode">
        <mat-icon *ngIf="showEditMode" (click)="toggleEditMode()">create</mat-icon>
        <div >
            <img class="profile-picture" [src]="user.imageUrl">
        </div>
        <mat-card-title>{{user.firstName}} {{user.lastName}}</mat-card-title>
    </div>
    <div *ngIf="editMode" class="dropzone" appDropzone (hovered)="toggleHover($event)" (dropped)="startUpload($event)" [class.hovering]="isHovering">
        <mat-card-title>Upload new image</mat-card-title>
        <mat-card-subtitle>Drag and drop a file</mat-card-subtitle>
        <div class="file">
            <label class="file-label"></label>
            <input type="file" (change)="startUpload($event.target.files)">
        </div>
        <mat-progress-bar *ngIf="percentage$ | async as percentage" mode="determinate" value="percentage" max="100"></mat-progress-bar>
        <div *ngIf="snapshot$ | async as snapshot">{{snapshot.bytesTransferred.toFixed(0)}}</div>
        <div *ngIf="downloadUrl$ | async as downloadUrl">
            <h3>The result:</h3>
            <img class="result" [src]="downloadUrl">
        </div>
    </div>
</mat-card>

相应文件中的 ts 代码是这样的:

export class UserComponent implements OnInit {

  @Input()
  user$: Observable<User>;

  @Input()
  editMode: boolean = false;

  @Input()
  showEditMode: boolean;

  task: AngularFireUploadTask;
  percentage$: Observable<number>;
  snapshot$: Observable<any>;
  downloadUrl$: Observable<string>;
  isHovering: boolean;
  sideNavigationStatus: boolean;
  uidFromActiveUser: string;

  constructor(private angularFireStorage: AngularFireStorage, private angularFirestore: AngularFirestore, private dataService: DataService) { }

  ngOnInit() {
  }

  toggleEditMode(){
    this.editMode = true;
  }

  toggleHover(event: boolean){
    this.isHovering = event;
  }

  startUpload(event: FileList) {
    const file = event.item(0);
    if(file.type.split('/')[0] !== 'image'){
      console.error('unsupported file type :( ');
      return;
    }
    const path = `image/${new Date().getTime()}_${file.name}`;
    this.task = this.angularFireStorage.upload(path, file);
    const fileRef = this.angularFireStorage.ref(path);
    this.percentage$ = this.task.percentageChanges();
    this.snapshot$ = this.task.snapshotChanges();
    this.snapshot$.pipe(
      tap(snapshot => {
        if (snapshot.bytesTransferred === snapshot.totalBytes){
        }
      }),
      finalize(() => {
        this.downloadUrl$ = fileRef.getDownloadURL();
        this.downloadUrl$.subscribe(link => {
          this.user$.subscribe(user => {
            this.dataService.updateUserImage(user, link);
          })
        })
        setInterval(() => this.editMode = false, 5000);
      })
    )
    .subscribe();
  }

}

该组件的使用为 showEditMode 提供了所需的值:

<app-user [user$]="user$" [editMode]="editMode" [showEditMode]="showEditMode"></app-user>

该组件用于名为 profile 的组件中,我在 ngOnInit() 中初始化 showEditMode:

ngOnInit() { 
    this.uidFromActiveUser = this.authenticationService.getUId();
    this.user$ = this.activatedRoute.paramMap.pipe(
      switchMap((params: ParamMap) => {
        if(this.uidFromActiveUser != params.get('uId')){
          this.showEditMode = false;
        } else { this.showEditMode = true };
        console.log('Ich bin die erste UID ' + params.get('uId'));
        return this.dataService.getUserData(params.get('uId'))
      })
    )
     this.incidents$ = this.activatedRoute.paramMap.pipe(
      switchMap((params: ParamMap) => {
        console.log('Ich bin die zweite UID ' + params.get('uId'))
        return this.dataService.getIncidentsFromUser(params.get('uId'))}
        )
    );
    this.incidents$.subscribe(incidents => console.log(incidents));
  }

我认为问题在于我初始化 showEditMode 值的生命周期钩子,但我不知道如何正确执行。

有人能帮我吗?谢谢!!

标签: angularangular-material

解决方案


您必须在组件中使用 AfterContentChecked 生命周期挂钩来避免此错误。

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

constructor(
  private cdref: ChangeDetectorRef) { }

ngAfterContentChecked() {
  this.cdref.detectChanges();
}

推荐阅读