Angular Dynamic形式可观察属性绑定

时间:2017-06-29 15:17:02

标签: forms angular ngrx

我遇到了一些动态生成的表单并将值传递给它们的问题。我觉得有人必须解决这个问题,或者我错过了一些明显的东西,但我无法提及它。

例如,我有三个组件,父母,孩子,然后是那个孩子的孩子。对于名称,我将使用,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获得的收益。

这似乎太过疏忽而没有解决方案,所以我假设只是我没有想到什么。有什么想法吗?

3 个答案:

答案 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并没有解雇,所以这不是一个完整的解决方案。我会继续深入研究它。