How to use formControlName and deal with nested formGroup?

FormsAngularAngular Reactive-Forms

Forms Problem Overview


As Angular documentation says we can use formControlName in our forms:

<h2>Hero Detail</h2>
<h3><i>FormControl in a FormGroup</i></h3>
<form [formGroup]="heroForm" novalidate>
    <div class="form-group">
        <label class="center-block">Name:
            <input class="form-control" formControlName="name">
        </label>
    </div>
</form>

As they say...

> Without a parent FormGroup, [formControl]="name" worked earlier because that directive can stand alone, that is, it works without being in a FormGroup. With a parent FormGroup, the name input needs the syntax formControlName=name in order to be associated with the correct FormControl in the class. This syntax tells Angular to look for the parent FormGroup, in this case heroForm, and then inside that group to look for a FormControl called name.

Anyway some months ago I asked this to figure out what is the difference between formControlName and [formControl].

Now my question is: what about use formControlName with nested FormGroups?

For example, if I have the following form structure:

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
	'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

What is the right way to bind "street" (or "houseNumber" or "postalCode") to related HTML elements using formControlName?

Forms Solutions


Solution 1 - Forms

you can use Form group which is basically a collection of controls ( controls mean the fields given in your html form) define in your typescript syntax and binded to your HTML elements using the formControlName directive ,for example

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
    'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

Template:

<form [formGroup]="myForm" >
   <div class="form-group">
      <label for="fullname">Username</label>
      <input type="text" id="username" formControlName="fullname" class="form-control">            
   </div>
   <div class="radio" *ngFor="let gender of genders">
      <label>
      <input type="radio" formControlName="gender" [value]="gender">{{ gender }} </label>
   </div>
   <div formGroupName="address">
      <div class="form-group">
         <label for="street">Username</label>
         <input type="text" id="username" value="street" formControlName="street" class="form-control">            
      </div>
      <div class="form-group">
         <label for="houseNumber">Username</label>
         <input type="text" id="username" value="street" formControlName="houseNumber" class="form-control">            
      </div>
      <div class="form-group">
         <label for="postalCode">Username</label>
         <input type="text" id="username" value="street" formControlName="postalCode" class="form-control">            
      </div>
   </div>
</form>

A formGroup can consist of a nested formGroup and hierarchy can continue on ,but in accessing the value the its fairly simple .

Solution 2 - Forms

It is true. Look at formGroupName

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
    'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

<form [formGroup]="myForm" >
   <div class="form-group">
      <label for="fullname">Username</label>
      <input type="text" id="username" formControlName="fullname" class="form-control">            
   </div>
   <div class="radio" *ngFor="let gender of genders">
      <label>
      <input type="radio" formControlName="gender" [value]="gender">{{ gender }} </label>
   </div>
   <div formGroupName="address">
      <div class="form-group">
         <label for="street">Username</label>
         <input type="text" id="username" value="street" formControlName="street" class="form-control">            
      </div>
      <div class="form-group">
         <label for="houseNumber">Username</label>
         <input type="text" id="username" value="street" formControlName="houseNumber" class="form-control">            
      </div>
      <div class="form-group">
         <label for="postalCode">Username</label>
         <input type="text" id="username" value="street" formControlName="postalCode" class="form-control">            
      </div>
   </div>
</form>

Solution 3 - Forms

tl;dr:

You can break your form up into components that use your nested formgroups, and formcontrolname can be used as normal.

The approach I tend to use, since usually nested Formgroups are used to designate separate parts of a form, is to break it up into components and pass those components the nested formgroup as an input parameter. So in your case, I would have an address component that takes a formgroup as a parameter:

<app-address [formGroup]="myForm.get('address')"></app-address

And inside of that component, I would just have an @Input() formGroup that would be used in the html:

<div [formGroup]="formGroup">
....

That way you can reference the control name explicitly as you normally would, since it would be part of this formgroup.

Also, keep in mind the form is passed as reference. your changes would be accounted for in the parent component's myForm element, and if you needed access to parts of the form not in you formgroup (validation, change detection, ect ect) you could always pass down the whole form and just define the formgroup to reference the inner group explicitly:

<div [formGroup]="formGroup.get('adress')">

(assuming you pass down the entire form object that is

Happy coding!

Solution 4 - Forms

> I am struggling with a problem in Angular 10. > I have a "parent" form group "forma" who has a few dependent groups: "company", and at the same time, "company" has two > "children" with another groups, msgAccounts and socialMedia. > When I fill the form and I submit it, in the backend everything is correct, I can see how these data is stored in the db > correctly, but when I receive this json I cannot display the data > inside "company.msgAccounts" and "company.socialMedia" in the controls > (inputs). This is what I get from the server:

            {
            name:'',
            active: '',
            ........
            company:{
              msgAccounts:{line: "@linedemo", whatsapp: "0325554244"},
              socialMedia: {fb: '', tw: '', is: ''}
             }   
            ..........
            }
    
 this.forma = this.fb.group( {
          siteName  : [ '', [Validators.required, Validators.minLength(5)]],
          siteEmail  : [ '', [Validators.required, Validators.minLength(5)]],
          // defaultLocation: [ '', [Validators.required, Validators.minLength(10)]],
          active  : [ true, [Validators.required, Validators.minLength(5)]],
          mainLanguage: ['' , [Validators.required, Validators.minLength(2)]],
        
          company: this.fb.group({
            name: [''],
            address: [''],
            phone: [''],
            msgAccounts: this.fb.group({
              line: [],
              whatsapp: []
            }),
            socialMedia: this.fb.group({
              fb: [],
              is: [],
              tw: []
            })
          })
        });
    
    And the html: (Sorry about the indentation, when it was not easy using this editor, and I just pasted a part of the code in order to do it as shorter as possible).
    
            <mat-tab-group>   
                    <mat-tab label="settings">
                        <form autocomplete="off" >
                            <ng-template ng-template matTabContent> 
                                <mat-tab-group  [formGroup]="forma">
                                        <mat-tab label="global"> 
                                           // All this fields have are fine
                                         </mat-tab>
    
                                 <mat-tab formGroupName="company" label="company"> 
                                    <div class="card">
                                        <div class="card-header" id="headingTwo">
                                            <h5 class="mb-0">Details</h5>
                                        </div>
                                        <div id="company-details">
                                                <div class="form-group row">
                                                    <div class="col-sm-3">
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="name" 
                                                        name="name"
                                                        placeholder="Company name"
                                                        formControlName=name>
                                                    </div>
                        
                                                </div>
    
                             <div class="form-group row" formGroupName="msgAccounts">
                                                    <div class="col-sm-6">
                                             
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="line" 
                                                        name="line"
                                                        placeholder="line"
                                                        formControlName=line>
                                                    </div>
                                                    <div class="col-sm-6">
                                                    
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="whatsapp" 
                                                        name="whatsapp"
                                                        placeholder="whatsapp"
                                                        formControlName=whatsapp>
                                                    </div>
                                                </div>
    
                                                	
    
                             <div class="form-group row" formGroupName="socialMedia" >
                         
                                                    <div class="col-sm-6">
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="is" 
                                                        name="is"
                                                        placeholder="Is"
                                                        formControlName=is>
                                                    </div>
                                                </div>                             
                                            </div>
                                       </div>
                                </mat-tab>                 
               </mat-tab-group>  
                            <div class="form-group row">
                            <div class="col-sm-10">
                               <button type="submit" 
                                   (click)="saveConfig()">Save</button>
                            </div>
            </div>
                        
           </ng-template>
          </form>
       </mat-tab>
    </mat-tab-group>  

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsmartmouseView Question on Stackoverflow
Solution 1 - FormsSomdatt_BhadvariyaView Answer on Stackoverflow
Solution 2 - FormsAlbert NizamutdinovView Answer on Stackoverflow
Solution 3 - FormsiamawordView Answer on Stackoverflow
Solution 4 - FormsR0bertinskiView Answer on Stackoverflow