当Component
的子项并非总是被创建时,我正在努力寻找一种管理*ngIf
的子项的好方法。
组件RootComponent
的HTML结构:
<div id="root-div" *ngIf="dto">
<div id="nested-div-1" *ngIf="something">
<my-nested-component>
</my-nested-component>
</div>
<div id="nested-div-2" *ngIf="somethingElse">
<div #anotherChild>
</div>
</div>
<button (onClick)="setSomethingElse()">Button</button>
</div>
问题:
RootComponent
已呈现。REST
中调用 ngAfterViewInit
以获得dto
,直接设置something
布尔值
@ViewChild() myNestedComponent : MyNestedComponent;
ngAfterViewInit() {
restService.get().then((result) => {
this.dto = result;
this.something = true;
}
}
Angular现在将渲染root-div
,nested-div-1
和my-nested-component
。
执行以下操作时,您将获得undefined
异常:
@ViewChild() myNestedComponent : MyNestedComponent;
ngAfterViewInit() {
restService.get().then((result) => {
this.dto = result;
this.something = true;
this.myNestedComponent.theMethod();
}
}
这很合理,因为Angular尚未更新视图,因此myNestedComponent
未定义
错误/棘手的解决方案
ChangeDetectorRef.detectChanges()
强制Angular更新视图this.myNestedComponent.theMethod()
包裹在setTimeout
中,这会延迟该行的执行,直到Angular完成周期为止。更好的解决方案
给my-nested-component
一个@Output
事件,以便my-nested-component
可以在完成初始化后在RootComponent
中执行一个方法(例如,在{{1}中) ngAfterViewInit
中的}
my-nested-component
这种方法的问题在于,当RootComponent想要对myNestedComponent进行操作时,需要检查<my-nested-component (afterInit)="nestedComponentInitialized()"></my-nested-component>
nestedComponentInitialized() {
this.myNestedComponentIsInitalized = true;
this.myNestedComponent.theMethod(); // Works now!
}
使用this.myNestedComponentIsInitalized
的setter时可以避免这种初始化方法。但每个@ViewChild()
@ViewChild
将myNestedComponent: MyNestedComponent;
@ViewChild() set myNestedComponentSetter(myNestedComponent: MyNestedComponent) {
this.myNestedComponentIsInitalized = true;
this.myNestedComponent = myNestedComponent;
}
更改为@ViewChild
,以便可以侦听该列表的更改,这意味着该组件是初始化的。
@ViewChildren
这种方法的问题在于,您只能侦听列表中的更改,当您已经知道@ViewChildren() myNestedComponents : QueryList<MyNestedComponent>;
ngAfterViewInit() {
restService.get().then((result) => {
this.dto = result;
this.something = true;
this.myNestedComponents.changes.subscribe(() => {
this.myNestedComponentIsInitalized = true;
this.myNestedComponents[0].theMethod();
}
}
}
中只有一个MyNestedComponent
时,这很奇怪。这样做的好处是您可以订阅初始化事件。
例如,当您有4个不同的嵌套组件时,这三个“更好的解决方案”将成为噩梦。因为这意味着RootComponent
需要4个初始化方法(或4个RootCompoment
),并且需要4个布尔值来嵌套组件的状态。管理所有这些变得非常复杂。
不要使用QueryList
,而要使用*ngIf
,以便一切都永远存在。这听起来不错,但这意味着所有内容始终都会渲染,并且有时您仍然需要检查是否存在某些内容。因为这是不可能的(因为[hidden]
可能引发异常,因为dto.name
尚未通过dto
调用进行初始化):
REST
优雅的解决方案?
我正在寻找一种解决方案,可以管理由于<div id="root-div" [hidden]="dto">
<div id="nested-div-1" [hidden]="something">
<my-nested-component>
</my-nested-component>
</div>
<div id="nested-div-2" [hidden]="!somethingElse">
<div #anotherChild>
<span>{{dto.name}}</span> <!-- EXCEPTION, dto is not there yet! -->
</div>
</div>
<button (onClick)="setSomethingElse()">Button</button>
</div>
条件而并非总是初始化的组件的状态。
我想做类似的事情:
*ngIf
和my-nested-component
。anotherChild
初始化(因此anotherChild
和my-nested-component
为true,并且anotherChild
为dto
时将somethingElse
的组件引用传递给my-nested-component
也在那里(所以something
也是如此)当嵌套的Component
由于* ngIf而并不总是存在时,管理它们的最佳模式或方法是什么?
答案 0 :(得分:2)
我认为最好的解决方案是针对容器/组件方法设计角度项目。
这意味着您具有处理数据的容器(父级)和仅基于输入值呈现的子级。所有导致数据更新的操作都应通过子级向其父级的输出发出,父级更新数据,并通过输入将更新后的数据再次传递给子级。
因此您的数据流将始终像这样:service-> container-> component。
该概念主要来自于磁通/ redux模式和反应,但在角度方面也提供了很多优势。好处是:
对于Rest请求,也可以将异步管道与ngIf结合使用,当所有数据可用时,将渲染您的孩子。在这里看看:https://toddmotto.com/angular-ngif-async-pipe
可以在以下位置找到有关容器/组件结构的良好指南:https://www.thegreatcodeadventure.com/the-react-plus-redux-container-pattern/
我知道这是一个巨大的话题,我无法在一篇文章中解释其所有复杂性,但是也许它会给您一些启发。