Angular add FormGroup to FormGroup

alphapilgrim picture alphapilgrim · Feb 21, 2019 · Viewed 9k times · Source

I have a parent component which is the main FormGroup. Inside this <my-parent></my-parent> component I have a child component, <my-child></my-child>.

The child component has a *ngIf="some-conditional", and inside the child component, I have a quick fill button which basically does patchValue on a couple of the child FormGroup controls.

It successfully adds the child FormGroup to parent FormGroup, but the values of the child inside of the parent are always empty.

I've tried to add the controls two ways(both unsuccessful), with a setter inside the parent component, and by emitting from inside the child component and reassigning the new value to the parent FormGroup.

Here's a stackblitz with a demo of what im trying to do. Thanks in advance!

// PARENT COMPONENT

import {
  Component,
  ViewChild
} from '@angular/core';
import {
  FormBuilder,
  FormGroup,
  Validators
} from '@angular/forms';

import {
  ChildComponent
} from './child.component';

@Component({
  selector: 'my-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./app.component.scss']
})
export class ParentComponent {
  isChildFormSet = false;
  showChildComponent = false;
  exampleParentForm: FormGroup;

  // @ViewChild(ChildComponent)
  // set userForm(childForm: ChildComponent) {
  //   if (childForm && !this.isChildFormSet) {
  //     this.isChildFormSet = true;
  //     setTimeout(() => {
  //       this.exampleParentForm.addControl('child', new FormGroup(childForm.exampleChildForm.controls));
  //     });
  //   }
  // }

  constructor(private fb: FormBuilder) {
    this.exampleParentForm = this.fb.group({
      parent: ['', Validators.required]
    })
  }

  submitForm(): void {
    console.log(this.exampleParentForm)
  }

  addChildComponent(): void {
    this.showChildComponent = true;
  }

  onChange(form) {
    // reset the form value to the newly emitted form group value.
    this.exampleParentForm = form;
  }
}


// CHILD COMPONENT

import {
  Component,
  OnInit,
  Input,
  Output,
  EventEmitter
} from '@angular/core';
import {
  FormBuilder,
  FormGroup,
  Validators
} from '@angular/forms';

@Component({
  selector: 'my-child',
  templateUrl: './child.component.html',
  styleUrls: ['./app.component.scss']
})
export class ChildComponent implements OnInit {
  exampleChildForm: FormGroup;

  @Input() formData: FormGroup;
  @Output() onFormGroupChange: EventEmitter < FormGroup > = new EventEmitter < FormGroup > ();


  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.exampleChildForm = this.fb.group({
      child: ['', Validators.required]
    });

    this.addGroupToParent();
  }

  fillWithText() {
    this.exampleChildForm.patchValue({
      child: 'This is an exmple.'
    });
  }

  clearText(): void {
    this.exampleChildForm.get('child').setValue('');
  }

  private addGroupToParent(): void {
    this.formData.addControl('child', new FormGroup(this.exampleChildForm.controls));
    this.onFormGroupChange.emit(this.formData);
  }
}
<!-- PARENT COMPONENT -->

<div class="parent-container">
  <form [formGroup]="exampleParentForm" (submit)="submitForm()" novalidate>
    <div class="col-3">
      <input class="effect-1" type="text" placeholder="Parent Input" formControlName="parent" />
      <span class="focus-border"></span>
    </div>
    <my-child *ngIf="showChildComponent" [formData]="exampleParentForm" (onFormGroupChange)="onChange($event)">
    </my-child>
    <div>
      <button class="button parent" type="submit">Log Form Value</button>
    </div>
  </form>
  <button class="button small" type="button" (click)="addChildComponent()">Add Child Component</button>
</div>

<!-- CHILD COMPONENT -->

<div class="child-container" [formGroup]="exampleChildForm">
  <div class="col-3">
    <input class="effect-1" type="text" placeholder="Child Input" formControlName="child">
    <span class="focus-border"></span>
  </div>
  <div>
    <button class="button child" type="button" (click)="fillWithText()">Patch Value</button>
  </div>
</div>

Answer

yurzui picture yurzui · Feb 21, 2019

Instead of adding new FormGroup instance to the parent group simply add the child form group itself.

So

this.formData.addControl('child', new FormGroup(this.exampleChildForm.controls));

becomes

this.formData.addControl('child', this.exampleChildForm);

Forked Stackblitz