角嵌套表单父/子组件

时间:2018-10-23 11:49:38

标签: angular angular-reactive-forms

我有一个嵌套的反应形式,我想将其拆分为几个部分。

高级形式(父母)

advanced.component.ts

我定义了基本表单,但是我想避免为父级子组件定义表单模型,因为我认为它们不属于这里。

  buildChamberForm() {
    return this.formBuilder.group({
      _id: [''],
      __v: [''],
      name: [ '', Validators.required ],
      cycle: [ '', Validators.required ],
      strains: this.formBuilder.array([])
      rules: this.formBuilder.array([])
    })
  }

  buildChambersForm() {
    return  this.formBuilder.group({
      chambers: this.formBuilder.array( [] )
    })
  }

advanced.component.html

<app-setting-strains [chamberStrains]="chamber.strains" [chamberCycle]="chamber.cycle"></app-setting-strains>
<app-setting-lights [chamberRules]="chamber.rules" [chamberCycle]="chamber.cycle"></app-setting-lights>
<app-setting-fans [chamberRules]="chamber.rules"></app-setting-fans>

设置风扇(第一个孩子)

分庭规则分为不同的子部分,例如粉丝规则。

<app-input-rule [chamberRules]="chamberRules"  [ruleDevice]="'fan'" placeholder="'e.g. Air circulation (Left)'"></app-input-rule>

输入规则表格(第二个孩子)

在(某些)子组件中,使用输入规则格式。其他子组件使用其他输入组件。

input-rule.component.ts

  createRuleForm(device?, trigger?) {

    const ruleForm = this.formBuilder.group({
      _id: [''],
      sensor: [''],
      device: [device || ''],
      forDetector: [''],
      detectorId: [''],
      trigger: [trigger || ''],
      startTime: [''],
      durationHOn: [''],
      durationOn: [''], // TODO: this is temporary
      timeUnit: [''], // TODO: this is temporary
      durationMSOn: [''],
      onValue: [''],
      offValue: [''],
      onPattern: [''],
      durationMBlocked: [''],
      nightOff: [''],
      relay: ['']
    })
    return ruleForm
  }
  createRulesForms() {
    const rulesForm = this.formBuilder.group({
      rules: this.formBuilder.array( [] ) // TODO: validator depending on rule type
    })
    // console.log("rulesForm", rulesForm)
    return rulesForm
  }

input-rule.component.html

这是在输入规则组件中使用组件的示例。输入规则组件中有多个输入。

<div class="row">
  <div class="col-xs-12 col-sm-12 col-md-8">
    <app-input-relay *ngIf="rule.get('relay')" [label]="capitalizeFirstletter(ruleDevice) + 'Relay'" [class]="'tutorial-step'" [relay]="rule.get('relay')" [placeholder]="placeholder"></app-input-relay>
  </div>
</div>

输入继电器(第三个子节点),input-relay.component.html

输入继电器是设置规则参数的几个组件之一。

 <div class="form-group col-xs-6 col-sm-6" *ngIf="relay.value">
    <label>Rename Relay</label>
    <input type="text" class="form-control" [ngClass]="class" [formControl]="name" [placeholder]="placeholder" (keyup)="debouncedRename(this.relay.value, this.name.value)"/>
  </div>

目标

  • 将子表单保留在子组件中,而不是在父组件中定义整个表单。或者,如果这是将所有内容都移到表单构建器服务中的正确方法,那么

    • 在父表单上使用Submit方法开始对ll个子表单的验证=>从子表单中传递数据

问题

在我当前的设置中,我无法使用setValue来初始化高级组件中的表单,因为高级组件不了解例如中的子表单。 FormArray strains因此出错:

There are no form controls registered with this array yet.

我可以使用patchValue解决此问题,但我认为这是反模式的。

  1. 是否最好在parent.component中定义表单,还是应该将所有内容移到具有所有表单构建方法的服务中?

    1.1如果我将其留在父母中,该怎么做?

    1.2如果我将其移至服务,则该服务应该是有状态的并包含表单值,还是最好像在上面的html示例中那样使用输入在服务中窥视该表单并将其传递下来?

    1.2.1我也需要输出吗?我读到某个地方,反应形式以某种方式处理了这个问题。

那些有用的问题,但基本上都只是一个问题,什么是将复杂的嵌套形式分为几个部分的正确方法。

编辑:

在带有服务的示例中:

https://blog.grossman.io/real-world-angular-reactive-forms/

但是大多数示例都将表单逻辑放入组件中(但是它们也没有显示如何在组件之间进行拆分):

这个使用输入/输出:

(但我读到某处不应该使用反应式表单)

2 个答案:

答案 0 :(得分:0)

我遇到了相同的问题,但模板驱动表单。在所有子组件中,我声明:

@Component({
    ...
    viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],
})

由于这一点,我为将表单拆分为子组件的单个NgForm句柄。我不确定这个概念是否适用于反应形式。

答案 1 :(得分:0)

您可以在父组件中维护一个FormGroup,它将通过@input传递给子组件。在子组件内部,可以使用addControls()添加任何输入控件。

可以使用formGroup.value在父组件中访问这些子组件值。