【问题标题】:ExpressionChangedAfterItHasBeenCheckedError when passing value to component向组件传递值时出现 ExpressionChangedAfterItHasBeenCheckedError
【发布时间】:2019-09-11 18:06:50
【问题描述】:

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

<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 值的生命周期钩子,但我不知道如何正确执行。

有人可以帮助我吗?谢谢!!

【问题讨论】:

标签: angular angular-material


【解决方案1】:

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

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

constructor(
  private cdref: ChangeDetectorRef) { }

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

【讨论】:

    【解决方案2】:

    我认为你最好将用户组件传递给实际的用户对象,而不是可观察的。请尝试:

    <app-user *ngIf="(user$ | async) as user" [user]="user" [editMode]="editMode" [showEditMode]="showEditMode"></app-user>
    

    在组件中将 user$ 更改为:

       @Input() user: User;
    

    在用户 HTML 中:

    <mat-card *ngIf="user">
    

    【讨论】:

    • 非常感谢,我马上试试。但我应该说,问题不在于用户变量,它可能是由在 editMode 变量中检测到的变化引起的,这根本不是可观察到的。
    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-17
    • 1970-01-01
    • 2020-09-02
    • 2019-07-18
    相关资源
    最近更新 更多