Angular 角度4变化检测表达式ChangedTerrithasBeenCheckedError
我试图解决AngularJS中不存在的问题,因为Angular 角度4变化检测表达式ChangedTerrithasBeenCheckedError,angular,typescript,angular2-changedetection,Angular,Typescript,Angular2 Changedetection,我试图解决AngularJS中不存在的问题,因为$digest-循环检查所有内容 我正在尝试创建一个组件,它可以初始化自身(异步),并通知其周围的容器加载已经完成 我有一个伪表: > 在周围的组件(包含行)中,我有一个函数onClickRow(row),它可以切换行 在my component组件中,我想将row.isLoading设置为true(通知“父”行它正在加载),然后在API调用完成后将其设置为false @Input()数据:任意; 恩戈尼尼特(){ this.task.islo
$digest
-循环检查所有内容
我正在尝试创建一个组件,它可以初始化自身(异步),并通知其周围的容器加载已经完成
我有一个伪表:
>
在周围的组件(包含行
)中,我有一个函数onClickRow(row)
,它可以切换行
在my component
组件中,我想将row.isLoading
设置为true(通知“父”行它正在加载),然后在API调用完成后将其设置为false
@Input()数据:任意;
恩戈尼尼特(){
this.task.isload=true;//问题
setTimeout(()=>{//simulate API调用
this.task.isload=false;//没问题
}, 2000);
}
现在我得到了这个错误:error:expressionChangedTerithasBeenCheckedError:Expression在被检查后发生了更改。以前的值:“未定义”。当前值:“true”。
我想这是因为更改从树上的my component
到ng container
,然后不是向下到my table row
我有一个解决方法,我可以使用第二个setTimeout()
,在this.task.isLoading
的第一个设置周围,但是这会导致一些popin效果,如果可能的话,我想找到一个更干净的解决方案
有人有什么建议吗?这是如何实现的?我找到了一个可以接受的解决方案
您可以将“父级”注入组件(类似于AngularJS中的require
)
为此,您需要将my table行
和my detail行
合并为类似my item行
的内容。这还有一个额外的好处,即您可以将切换逻辑放入组件中,而不必在每次使用时都重新实现它
my item row.component.html
:
<div
class="item-row"
(click)="onToggleDetail()"
>
<div class="cell">...</div>
<div *ngIf="isLoading" class="loading"></div>
</div>
<div
*ngIf="isExpanded"
[hidden]="!isInitialized"
class="detail-row"
>
...
</div>
现在,您可以将其注入我的组件
,如下所示:
my component.component.ts
:
import { Component } from '@angular/core';
import { Input, ChangeDetectorRef } from '@angular/core';
@Component({...})
export class MyItemRowComponent {
...
isInitialized: boolean = false;
isLoading: boolean = false;
isExpanded: boolean = false;
constructor(private changeDetector: ChangeDetectorRef) { }
onToggleDetail() : void {
this.isExpanded = !this.isExpanded;
}
public startLoading() : void {
this.isLoading = true;
this.isInitialized = false;
this.changeDetector.detectChanges(); // trigger re-evaluate
}
public stopLoading() : void {
this.isLoading = false;
this.isInitialized = true;
this.changeDetector.detectChanges(): // trigger re-evaluate
}
}
import { Component } from '@angular/core';
import { Input, Host, Optional } from '@angular/core';
import { MyItemRowComponent } from '...';
@Component({...})
export class MyComponentComponent {
...
// Optional, because there may be a case where we want to use it outside of a row
constructor(@Optional() @Host() private parent: MyItemRowComponent) { }
ngOnInit() { // or ngAfterViewInit, doesn't matter
if (this.parent) {
this.parent.startLoading();
}
setTimeout(() => { // simulate API call
if (this.parent) {
this.parent.stopLoading();
}
}, 2000);
}
}
这是我目前的解决方案
这会导致启动my组件时出现不同的问题,即使它尚未展开,请参见此处:
非常详细地解释了这种行为。为什么不总是使用任务初始化。isLoading=true
并且不从my component中设置它,而是在加载组件时只更新为false
,这将按照您所说的异步完成,您将不会有这种情况problem@Maximus我不能将isLoading=true
作为默认值,它控制我的表格行的可见行为
(显示加载指示器)。这个链接很有帮助,但有点告诉我,除了承诺/暂停之外,我别无选择,因为我正在做一些我不应该做的事情。但是现在我想不出任何其他方法来实现这一点,在my component
子组件中有一个包含所有逻辑的“哑”表/包装组件。