我遇到了一些动态生成的表单并将值传递给它们的问题。我觉得有人必须解决这个问题,或者我错过了一些明显的东西,但我无法提及它。
例如,我有三个组件,父母,孩子,然后是那个孩子的孩子。对于名称,我将使用,formComponent,questionComponent,textBoxComponent。两个孩子都在使用changeDetection.OnPush。
因此,form组件通过输入将一些值传递给questionComponent,而有些则使用异步管道来订阅商店中各自的值。
QuestionComponent动态创建不同的组件,如果它们匹配则将它们放在页面上(这么多类型的组件,但每个questionComponent只处理一个组件。
一些代码:
@Input() normalValue
@Input() asyncPipedValue
@ViewChild('questionRef', {read: ViewContainerRef}) public questionRef: any;
private textBoxComponent: ComponentFactory<TextBoxComponent>;
ngOnInit() {
let component =
this.questionRef.createComponent(this.checkboxComponent);
component.instance.normalValue = this.normalValue;
component.instance. asyncPipedValue = this. asyncPipedValue;
}
这适用于normalValues的所有实例,但不适用于asyncValues。我可以在questionComponent的ngOnChanges中确认该值正在更新,但该值未传递给textBoxComponent。
我基本上需要的是异步管道,但不适用于模板。我尝试了多种方法来传递asyncValues,我尝试检测asyncPipeValue何时更改,并在textBoxComponent上触发changeDetectionRef.markForChanges(),但只有在我将changeDetectionStrategy更改为normal时才会有效,这有点会影响性能我从使用ngrx获得的收益。
这似乎太过疏忽而没有解决方案,所以我假设只是我没有想到什么。有什么想法吗?
答案 0 :(得分:1)
我做了类似的事情,我的表格来自我的Ngrx商店的数据。我的表单不是动态的,所以我不能100%确定这是否也适合你。
仅使用setter定义输入,然后在窗体/窗体控件上调用patchValue()或setValue()。您的根组件保持不变,使用异步管道将数据传递到下一个组件。
@Input() set asyncPipedValue(data) {
if (data) {
this.textBoxComponent.patchValue(data);
}
}
patchValue()在AbstractControl类上。如果您无法从问题组件访问该文档,则TextBoxComponent可以公开一个类似的方法,可以从QuestionComponent调用,并且实现执行控件的更新。
要注意的一件事是,如果您还在表单/控件上订阅了valueChanges,您可能需要设置第二个参数,以便valueChanges事件不会立即触发。
this.textBoxComponent.patchValue(data, { emitEvent: false });
或
this.textBoxComponent.setValue(...same as above);
然后在TextBoxComponent
中this.myTextBox.valueChanges
.debounceTime(a couple of seconds maybe)
.distinctUntilChanged()
.map(changes => {
this.store.dispatch(changes);
})
.subscribe();
这种方法运行良好,无需在任何地方保存/更新按钮。
答案 1 :(得分:0)
以下是我对该问题的看法,考虑到有限的代码段。
首先,提供的示例似乎与ngrx
没有任何关系。在这种情况下,预计ngOnInit
仅运行一次,此时this.asyncPipedValue
值为undefined
。因此,如果changeDetection
的{{1}}为this.checkboxComponent
,则该值不会更新。我建议阅读有关更改检测和传递异步输入的one excellent article。该文章还包含有关变更检测的其他资源。此外,似乎相同的输入在组件树中传递两次,从我的角度来看这不是一个好的解决方案。
其次,另一种方法是使用ChangeDetection.OnPush
,然后根本不需要传递任何异步输入。特别是,如果两个组件在组件树中没有父子关系,则这种方式很好。在这种情况下,一个组件调度操作以将数据放入Store,另一个组件从Store订阅该数据。
ngrx
希望这有助于或至少提供一些线索。
答案 2 :(得分:0)
我相信我已经找到了解决方案(在gitter.com/angular频道的帮助下)。
由于值会进入questionComponent可以更改,并触发它的ngOnChanges触发,只要ngOnChanges中有事件,它就需要解析整个事件,并绑定并更改为动态子节点零件。
ngOnChanges(event) {
if (this.component) {
_.forEach(event, (value, key) => {
if (value && value.currentValue) {
this.component.instance[key] = value.currentValue;
}
});
}
}
这就是问题组件,如果它们已经改变,它会重置组件实例变量。到目前为止,这个问题最大的问题是,孩子的ngOnChanges并没有解雇,所以这不是一个完整的解决方案。我会继续深入研究它。