1

I have a nested reactive form which I want to split into several components.

advanced form (parent)

advanced.component.ts

I define the basic form, but I would like to avoid to define the form models for the subcomponents in the parent, because I think they don't belong here.

  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>

setting-fans (1st child)

The chamber rules splits into different child components, e.g. rules for fans.

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

input-rule form (2nd child)

In (some of) those child components the input-rule form is used. Other child omponents use other input components.

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

This is an example of the use of a component in the input-rule component. There are several inputs in the input rule component.

<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 (3rd child), input-relay.component.html

Input relay is one of several components to set params of the rule.

 <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>

Goal

  • to keep the subforms in the child components, instead of defining the whole form in the parent component. Or if this is the right approach to move everything into a form builder service.

    • use the submit method on the parent form to start the validation of a ll subforms => passing up the data from the child forms

Questions

In my current setup I cannot use to setValue to initialize the form in the advanced component, beacause the advanced component has no knowledge about the subforms in e.g. the FormArray strains thus it errs:

There are no form controls registered with this array yet.

I can solve this problem by using patchValue but I think this in anti pattern.

  1. Is it better to define the form in the parent.component or should I move everything to a service which has all the form building methods?

    1.1 If I leave it in the parent, how to do this?

    1.2 If I move it to a service, should the service be stateful and contain the form values or is better to just geenrate the form in the service and pass it down like in the html example above with inputs?

    1.2.1 Will I need outputs for this as well, I read somewhere that the reactive form handles this somehow.

Those a serval questions but they are all basically one question, what is the right way to split a complex nested form into several components.

EDIT:

This in an example with a service:

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

But most examples put the form logic into the component (but they also do not show how to split between components):

This one uses Inputs/Outputs:

(but I read somewhere this shouldn't be done with reactive forms)

1
  • Hi, we (at work) have been working on that topic and I gave a proper answer you may want to check here stackoverflow.com/a/55457210/2398593 :) Commented Apr 1, 2019 at 14:13

1 Answer 1

0

You can maintain one FormGroup in parent component, that will be passed on @input to the child component. Inside Child Component, using addControls() we can add any input controls.

Those child components values can be accessed in parent component using formGroup.value.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.