Forms 角度动态形式可观测属性绑定

Forms 角度动态形式可观测属性绑定,forms,angular,ngrx,Forms,Angular,Ngrx,我对一些动态生成的表单和向它们传递值有问题。我觉得一定有人解决了这个问题,或者我遗漏了一些明显的东西,但我找不到任何提及 例如,我有三个组件,一个父,一个子,然后是该子的一个子。对于名称,我将使用,formComponent,questionComponent,textBoxComponent。两个孩子都在使用changeDetection.OnPush 所以表单组件通过输入将一些值向下传递给questionComponent,而一些则使用异步管道订阅存储中各自的值 QuestionCompon

我对一些动态生成的表单和向它们传递值有问题。我觉得一定有人解决了这个问题,或者我遗漏了一些明显的东西,但我找不到任何提及

例如,我有三个组件,一个父,一个子,然后是该子的一个子。对于名称,我将使用,formComponent,questionComponent,textBoxComponent。两个孩子都在使用changeDetection.OnPush

所以表单组件通过输入将一些值向下传递给questionComponent,而一些则使用异步管道订阅存储中各自的值

QuestionComponent动态创建不同的组件,如果它们匹配,则将它们放置在页面上(组件类型太多,但每个QuestionComponent仅处理一个组件)

ngOnChanges(event) {
if (this.component) {
  _.forEach(event, (value, key) => {
    if (value && value.currentValue) {
      this.component.instance[key] = value.currentValue;
    }
  });
 }
}
一些代码:

@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;
}
@Input()正常值
@Input()异步PipedValue
@ViewChild('questionRef',{read:ViewContainerRef})公共questionRef:any;
私有textBoxComponent:ComponentFactory;
恩戈尼尼特(){
让组件=
this.questionRef.createComponent(this.checkboxComponent);
component.instance.normalValue=this.normalValue;
component.instance.asyncPipedValue=此.asyncPipedValue;
}
这适用于所有normalValues实例,但不适用于asyncValues。我可以在questionComponent的ngOnChanges中确认该值正在更新,但该值不会传递给textBoxComponent

ngOnChanges(event) {
if (this.component) {
  _.forEach(event, (value, key) => {
    if (value && value.currentValue) {
      this.component.instance[key] = value.currentValue;
    }
  });
 }
}
我基本上需要的是异步管道,但不是用于模板。我尝试了多种方法来传递异步值,我尝试了检测asyncPipeValue何时更改,以及触发changeDetectionRef.markForChanges()在textBoxComponent上,但这只在我将changeDetectionStrategy更改为normal时起作用,这有点挫败了我使用ngrx获得的性能提升


这似乎是一个太大的疏忽,以至于现在还没有解决方案,所以我假设只是我没有思考一些事情。有什么想法吗?

考虑到有限的代码片段,下面是我对这个问题的想法

首先,提供的示例似乎与
ngrx
没有任何关系。在这种情况下,预期
ngOnInit
只运行一次,此时
this。asyncPipedValue
值是
未定义的
。因此,如果
changeDetection
。checkboxComponent
ChangeDetection.OnPush
该值不会得到更新。我建议阅读有关更改检测和传递异步输入的内容。该文章还包含其他关于更改检测的重要资源。此外,似乎相同的输入会在组件树中传递两次,从我的观点来看,这不是一个好的解决方案

其次,另一种方法是使用
ngrx
,然后您根本不需要传递任何异步输入。特别是,如果两个组件在组件树中没有父子关系,这种方法是很好的。在这种情况下,一个组件调度操作将数据放入存储,另一个组件订阅来自商店

export class DataDispatcherCmp {

    constructor(private store: Store<ApplicationState>) {
    }

    onNewData(data: SomeData) {
        this.store.dispatch(new SetNewDataAction(data));
    }
}

export class DataConsumerCmp implements OnInit {

    newData$: Observable<SomeData>;

    constructor(private store: Store<ApplicationState>) {
    }

    ngOnInit() {
        this.newData$ = this.store.select('someData');
    }
}
导出类DataDispatcherCmp{
构造函数(私有存储:存储){
}
onNewData(数据:SomeData){
this.store.dispatch(newsetnewdataaction(data));
}
}
导出类DataConsumerCmp实现OnInit{
newData$:可观察的;
构造函数(私有存储:存储){
}
恩戈尼尼特(){
this.newData$=this.store.select('someData');
}
}

希望这能有所帮助或至少能提供一些线索。

我相信我已经找到了解决方案(在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;
    }
  });
 }
}

这都是questionComponent,如果组件实例变量发生更改,它会重置这些变量。到目前为止,最大的问题是,孩子的ngOnChanges没有启动,因此这不是一个完整的解决方案。我将继续深入研究。我做了类似的事情,从我的NgoRx存储区的数据填充表单。我的表单不是动态的,所以我不能100%确定这是否也适用于您

使用setter定义输入,然后在表单/表单控件上调用patchValue()或setValue()。根组件保持不变,使用异步管道将数据传递到下一个组件

@Input() set asyncPipedValue(data) {
  if (data) {
    this.textBoxComponent.patchValue(data);
  }
}
patchValue()位于AbstractControl类上。如果您没有从question组件访问该类的权限,则TextBoxComponent可以公开类似的方法,该方法可以从QuestionComponent调用,实现将执行控件的更新

但是需要注意的一点是,如果您也在表单/控件上订阅valueChanges,则可能需要设置第二个参数,以便valueChanges事件不会立即触发

this.textBoxComponent.patchValue(data, { emitEvent: false });

然后在TextBoxComponent中

this.myTextBox.valueChanges
  .debounceTime(a couple of seconds maybe)
  .distinctUntilChanged()
  .map(changes => {
    this.store.dispatch(changes);
  })
  .subscribe();

这种方法工作得很好,不需要到处都有保存/更新按钮。

你能提供plunker吗?你研究过BehaviorSubject吗?你可以让一个服务运行逻辑和/或修改你的asyncValue作为BehaviorSubject,让每个组件订阅该BehaviorSubject的可观察项。^为什么我们需要
BehaviorSubject
当使用ngrx时,我们可以只存储在“store”中,对吗?@Austin您可以在不让组件相互交互的情况下完成大部分工作,您对此满意吗,或者在通信中特别关注它们您可以尝试让您的输入不是作为值,而是作为可观察的。类似@input()的东西asyncPipedValue:Observable;因此同一个输入不会被传递两次,而是从父级传递给子级,然后必须传递给另一个子级。第一个子级的输入是