Angular ngModelGroup Example

By Arvind Rai, 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.

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, use ngModelGroup 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> 
In the above code, addressGroup is grouping vill, post and dist input elements. Using addressGroup, we can get, set and validate its fields.
1. Find the TS code to fetch addressGroup value on form submit.
onFormSubmit(form: NgForm) {
	console.log(form.controls['addressGroup'].value);
} 
2. Find the code to fetch vill field of address
console.log(form.controls['addressGroup'].get('vill')?.value); 
3. Find the code to fetch post field of address
console.log(form.controls['addressGroup'].get('post')?.value); 
4. Find the code to fetch dist field of address
console.log(form.controls['addressGroup'].get('dist')?.value); 
5. On HTML template, to display values of addressGroup, use json pipe.
{{addressCtrl.value | json}} 
addressCtrl is the template reference variable.

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> 
addressGroup will be considered validated only when all its fields will be validated. It means when vill, post and dist are validated, only then addressGroup is validated. The template reference variable addressCtrl will be the instance of NgModelGroup for this group of elements.
We can fetch validation properties as following.
1. Using status
{{ addressCtrl.status }} 
2. Using valid
{{ addressCtrl.valid }} 
3. Using invalid
{{ addressCtrl.invalid }} 
4. Using touched
{{ addressCtrl.touched }} 
5. Using dirty
{{ addressCtrl.dirty }} 
6. Use validation properties to display validation messages as following.
<div *ngIf="addressCtrl.invalid">
	Address not valid.
</div> 

3. Setting Default Values

To set default values to ngModelGroup, create an object in TS file that has fields for group elements.
ngOnInit() {
   addressGroup = { vill: 'Bhonda', post: 'Babatpur', dist: 'PrayagRaj' };
} 
Bind these value to group elements using 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> 
user.component.ts
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' };
	}
} 
user-service.ts
import { Injectable } from '@angular/core';

@Injectable({
    providedIn: 'root'
})
export class UserService {
    createUser(user: any) {
        console.log(user.value);
    }
} 
Find the print-screen of the output.
Angular ngModelGroup Example

5. Reference

6. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us