Angular ngModelGroup Example
January 12, 2024
On this page we will learn to use NgModelGroup
directive in our Angular application.
1.
NgModelGroup
is used to group the HTML elements that are using ngModel
in template-driven from.
2. In reactive form, to group the elements, we use
FormGroup
directive.
3.
ngModelGroup
is the selector of NgModelGroup
directive.
4.
NgModelGroup
extends AbstractFormGroupDirective
. Hence all the methods and properties of AbstractFormGroupDirective
are available to NgModelGroup
.
5. To create template reference variable, use
ngModelGroup
as #addressCtrl="ngModelGroup"
that is used to fetch values and validation of that group.
6. For validation we can use errors, status, valid, invalid, pending, pristine, dirty, touched etc.
Contents
1. Using ngModelGroup
Suppose we want to create user template-driven form that collects address with other informations. Address can have fields such as village, post, district etc. To group these fields, usengModelGroup
as following.
HTML code:
<form #userForm="ngForm" (ngSubmit)="onFormSubmit(userForm)"> <div ngModelGroup="addressGroup" #addressCtrl="ngModelGroup"> Village: <input name="vill" ngModel> Post: <input name="post" ngModel> District: <input name="dist" ngModel> </div> ------ </form>
1. Find the TS code to fetch addressGroup value on form submit.
onFormSubmit(form: NgForm) { console.log(form.controls['addressGroup'].value); }
console.log(form.controls['addressGroup'].get('vill')?.value);
console.log(form.controls['addressGroup'].get('post')?.value);
console.log(form.controls['addressGroup'].get('dist')?.value);
json
pipe.
{{addressCtrl.value | json}}
2. Validation
To validate group and display validation messages, create template reference variable as#addressCtrl="ngModelGroup"
.
Find the code.
<div ngModelGroup="addressGroup" #addressCtrl="ngModelGroup"> Village: <input name="vill" ngModel minlength="3"> Post: <input name="post" ngModel maxlength="10"> District: <input name="dist" ngModel required> </div>
addressCtrl
will be the instance of NgModelGroup
for this group of elements.
We can fetch validation properties as following.
1. Using status
{{ addressCtrl.status }}
{{ addressCtrl.valid }}
{{ addressCtrl.invalid }}
{{ addressCtrl.touched }}
{{ addressCtrl.dirty }}
<div *ngIf="addressCtrl.invalid"> Address not valid. </div>
3. Setting Default Values
To set default values tongModelGroup
, create an object in TS file that has fields for group elements.
ngOnInit() { addressGroup = { vill: 'Bhonda', post: 'Babatpur', dist: 'PrayagRaj' }; }
ngModel
property binding.
HTML code:
<div ngModelGroup="addressGroup" #addressCtrl="ngModelGroup"> Village: <input name="vill" [ngModel]="address.vill" minlength="3"> Post: <input name="post" [ngModel]="address.post" maxlength="10"> District: <input name="dist" [ngModel]="address.dist" required> </div>
4. Complete Example
user.component.html<h3>User Information</h3> <p *ngIf="isValidFormSubmitted" [ngClass]="'success'"> Form submitted successfully. </p> <form #userForm="ngForm" (ngSubmit)="onFormSubmit(userForm)"> <table> <div ngModelGroup="userNameGroup" #userNameCtrl="ngModelGroup"> <tr> <td colspan="2"><b>User Name:</b></td> </tr> <tr> <td>First name:</td> <td> <input name="first" [ngModel]="userNameGroup.first" required> </td> </tr> <tr> <td>Middle name: </td> <td> <input name="middle" [ngModel]="userNameGroup.middle" minlength="3"> </td> </tr> <tr> <td>Last name: </td> <td> <input name="last" [ngModel]="userNameGroup.last" maxlength="10"> </td> </tr> <tr> <td colspan="2"> <div *ngIf="userNameCtrl.invalid && userForm.submitted && !isValidFormSubmitted" ngClass="error"> User name not valid. </div> </td> </tr> </div> <br /> <div ngModelGroup="addressGroup" #addressCtrl="ngModelGroup"> <tr> <td colspan="2"><b>Address:</b></td> </tr> <tr> <td>Village:</td> <td> <input name="vill" [ngModel]="addressGroup.vill" minlength="3"> </td> </tr> <tr> <td>Post: </td> <td> <input name="post" [ngModel]="addressGroup.post" maxlength="10"> </td> </tr> <tr> <td>District: </td> <td> <input name="dist" [ngModel]="addressGroup.dist" required> </td> </tr> <tr> <td colspan="2"> <div *ngIf="addressCtrl.invalid && userForm.submitted && !isValidFormSubmitted" ngClass="error"> Address not valid. </div> </td> </tr> </div><br /> {{ addressCtrl.value | json }} <div ngModelGroup="empInfoGroup" #empInfoCtrl="ngModelGroup"> <tr> <td colspan="2"><b>Employment Info:</b></td> </tr> <tr> <td>Work from home?</td> <td> <input type="checkbox" name="wfh" [ngModel]="empInfoGroup.wfh"> </td> </tr> <tr> <td>Work Type: </td> <td> <input type="radio" value="frontend" name="workType" required [ngModel]="empInfoGroup.workType" #wtCtrl="ngModel"> Front-End <input type="radio" value="backend" name="workType" required [ngModel]="empInfoGroup.workType" #wtCtrl="ngModel"> Back-End <input type="radio" value="fullstack" name="workType" required [ngModel]="empInfoGroup.workType" #wtCtrl="ngModel"> Full-Stack <div *ngIf="wtCtrl.errors?.['required'] && userForm.submitted && !isValidFormSubmitted" ngClass="error"> Select work type. </div> </td> </tr> <tr> <td>Profile: </td> <td> <select name="profile" [(ngModel)]="empInfoGroup.profile" required #profileCtrl="ngModel"> <option value="developer">Developer</option> <option value="tester">Tester</option> <option value="lead">Lead</option> </select> <div *ngIf="profileCtrl.errors?.['required'] && userForm.submitted && !isValidFormSubmitted" ngClass="error"> Select profile. </div> </td> </tr> <tr> <td colspan="2"> <div *ngIf="empInfoCtrl.invalid && userForm.submitted && !isValidFormSubmitted" ngClass="error"> Info not valid. </div> </td> </tr> </div> <tr> <td colspan="2"> <br /><br /> <button>Submit</button> <button type="button" (click)="setDefaultValues()">Set Default</button> </td> </tr> </table> </form>
import { Component, OnInit } from '@angular/core'; import { FormsModule, NgForm } from '@angular/forms'; import { UserService } from '../services/user-service'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-template', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './user.component.html', styleUrls: ['./user.component.css'] }) export class UserComponent implements OnInit { userNameGroup!: any; addressGroup!: any; empInfoGroup!: any; isValidFormSubmitted = false; constructor(private userService: UserService) { } ngOnInit(): void { this.initialValue(); } onFormSubmit(form: NgForm) { this.isValidFormSubmitted = false; if (form.valid) { this.isValidFormSubmitted = true; } else { return; } console.log(form.controls['addressGroup'].value); console.log(form.controls['addressGroup'].get('vill')?.value); this.userService.createUser(form); this.initialValue(); } initialValue() { this.userNameGroup = { first: '', middle: '', last: '' }; this.addressGroup = { vill: '', post: '', dist: '' }; this.empInfoGroup = { wfh: false, workType: '', profile: '' }; } setDefaultValues() { this.userNameGroup = { first: 'Om', middle: 'Shiv', last: 'Shankar' }; this.addressGroup = { vill: 'Bhonda', post: 'Babatpur', dist: 'PrayagRaj' }; this.empInfoGroup = { wfh: true, workType: 'fullstack', profile: 'tester' }; } }
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class UserService { createUser(user: any) { console.log(user.value); } }