How to use formGroupName inside child components
Asked Answered
K

2

17

How do i use formGroupName inside child components? for example:

i have ParentFormComponent

    parentForm: FormGroup;
    constructor(private fb: FormBuilder, private http: Http) { }
    ngOnInit() {


 this.parentForm = this.fb.group({
        _general: this.fb.group ({
           ProjectName:''
       })
  })
 }

In the html:

  <form [formGroup]="parentForm" (ngSubmit)="submitForm()">
     <div formGroupName="_general">
        <mat-form-field>
             <input matInput placeholder="Project name" 
             formControlName="ProjectName">
        </mat-form-field>
    </div> 
  </form> 

it's working great but when i want to use child component it's not working:

<form [formGroup]="parentForm" (ngSubmit)="submitForm()">
          <app-child [parentForm]='parentForm'></app-child>
      </form> 

when i insert it to the child component:

<div formGroupName="_general">
            <mat-form-field>
                 <input matInput placeholder="Project name" 
                 formControlName="ProjectName">
            </mat-form-field>
        </div> 

and in the ts file

 @Input() parentForm:FormGroup;

i"m getting error: formGroupName must be used with a parent formGroup directive. You'll want to add a formGroup directive and pass it an existing FormGroup instance (you can create one in your class).

Kinswoman answered 3/12, 2018 at 5:51 Comment(1)
Refer this link it might help you.Controversial
O
37

Instead of Using input property binding Use FormGroupDirective

FormGroupDirective

This directive accepts an existing FormGroup instance. It will then use this FormGroup instance to match any child FormControl, FormGroup, and FormArray instances to child FormControlName, FormGroupName, and FormArrayName directives.

Use Viewproviders to provide controlContainer, Inject FormGroupDirective in your child component to get the parentform instance

app.parent.html

<form [formGroup]="parentForm">
  <app-child></app-child>
</form>

child.component.ts

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ControlContainer, FormGroupDirective, Validators, FormBuilder, NgModel } from '@angular/forms';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
  viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class ChildComponent implements OnInit {
  childForm;
  constructor(private parentF: FormGroupDirective) { }

  ngOnInit() {

    this.childForm = this.parentF.form;
    this.childForm.addControl('_general', new FormGroup({
      ProjectName: new FormControl('')
    }))

  }
}

child.component.html

<div formGroupName="_general">
     <mat-form-field>
                 <input matInput placeholder="Project name" 
                 formControlName="ProjectName"> 
      <mat-form-field>  
 </div>

Example:https://stackblitz.com/edit/angular-ezqupz

Olsewski answered 3/12, 2018 at 6:31 Comment(16)
Is there a way to add mutiple components with the same formGroupName ?Christiachristian
@Christiachristian what do you mean by multiple components?Nosography
i'm trying something like this in the CLI stackblitz.com/edit/angular-form-magicChristiachristian
It's works fine on stackblitz but not inside my appChristiachristian
Works thanks... i forgetted to use new FormGroup to build the parent formChristiachristian
why not just pass the formgroup as an input? <app-child [myFormGroup]="myForm.get('myFormGroup')"> or <app-child [myFormControl]="myForm.get('myFormControl')">Aegyptus
This works when the field is directly inside the form group defined by [formGroup] but formGroupName doesn't work for me. I'd have to use [formGroup]="parentForm.get('_general')" in this example. The example on stackblitz doesn't seem to use nested form groups. Is there a way to get formGroupName to work too?Malm
Do You want to get nested form group name inside custom component? @ClaudeMartinNosography
@Chellappanவ I just want to use formGroupName="foo" like I could when not using a custom component. I don't know why it doesn't work on my project. I get Cannot find control with name: 'xxx'. It works when I use [formGroup]="root.get('foo')" instead. Is there another directive I have to declare for it to work?Malm
If it possible can you please create stackblitz?Nosography
@Chellappanவ I forked yours: stackblitz.com/edit/angular-ynjdlm This doesn't work because I use formGroupName. See app.component.html to see how [formGroup] would work, but formGroupName doesn't.Malm
You could do something like this as a workaround: stackblitz.com/edit/angular-ssryuc.Nosography
If you are looking for more generic check this blog:medium.com/angular-in-depth/…Nosography
So I ended up implementing ControlValueAccessor. Then it works.Malm
How do you unit test components using this approach? How do you avoid No provider for FormGroupDirective? I've tried a number of approaches but none have worked.Asarum
@Asarum Can you create sample repo or something?Nosography
S
3

You don't even need to pass the formGroup to the child component, just provide a ControlContainer and use formGroupName like this:

parent html:

<form [formGroup]="parentForm">
  <app-child></app-child>
</form>

parent ts:

 this.parentForm = this.fb.group({
        _general: this.fb.group ({
           ProjectName:''
       })
  })

child html:

<div formGroupName="_general">
     <mat-form-field>
                 <input matInput placeholder="Project name" 
                 formControlName="ProjectName"> 
      <mat-form-field>  
 </div>

child ts:

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, ControlContainer, FormGroupDirective, Validators, FormBuilder, NgModel } from '@angular/forms';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css'],
  viewProviders: [{ provide: ControlContainer, useExisting: FormGroupDirective }]
})
export class ChildComponent implements OnInit {
  constructor() { }

  ngOnInit() {

  }
}

That way, your entire form configuration is in the parent component without splitting it into the childrens .ts, they only act as views.

Sideboard answered 24/10, 2022 at 14:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.