angular - 将值传递给组件时的 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 值的生命周期钩子,但我不知道如何正确执行。
有人能帮我吗?谢谢!!
解决方案
您必须在组件中使用 AfterContentChecked 生命周期挂钩来避免此错误。
import { ChangeDetectorRef, AfterContentChecked} from '@angular/core';
constructor(
private cdref: ChangeDetectorRef) { }
ngAfterContentChecked() {
this.cdref.detectChanges();
}
推荐阅读
- arrays - 如何使单元格根据所选时间段动态显示平均百分比?
- python - 如何修复输入和参数张量不在同一个设备上?
- aws-lambda - 如何构建 AWS Serverless 应用程序?
- c# - 每次在集合视图上滚动时,在 CollectionView 中添加接下来的 20 个元素
- gremlin - Gremlin:在更便宜的步骤之后调用昂贵的步骤是否可以作为一种优化?
- python - 为什么我的函数在我的循环中执行两次?
- python - 有没有一种方法或函数来勾勒二进制矩阵中的形状?
- javascript - 在 ChoiceType 字段值的函数中显示或隐藏 Twig 模板中的字段
- python - CS50 财务:/index 帮助显示正确的信息
- r - 从多个 NETCDF 文件中堆叠和提取单个变量