Forms are a crucial part of web applications, enabling users to input and submit data. Angular provides two primary ways to handle forms: Template-Driven Forms and Reactive Forms. In this article, we will explore Template-Driven Forms, covering their concepts, setup, validations, binding techniques, and real-world use cases.
Template-driven forms are simple, easy to implement, and ideal for small to medium-sized applications. They rely heavily on Angular’s directives and the NgForm
module to bind form inputs to data models.
Table of Contents
- Introduction to Template-Driven Forms
- Setting Up Angular Forms Module
- Basic Template-Driven Form Example
- Two-Way Data Binding with ngModel
- Form Submission
- Built-in Validations
- Displaying Validation Messages
- Accessing Form Values and Status
- Resetting and Prefilling Forms
- Handling Nested Forms
- Dynamic Form Controls
- Custom Validation
- Form Events
- Real-World Example: User Registration Form
- Best Practices for Template-Driven Forms
- Common Pitfalls and How to Avoid Them
- Conclusion
1. Introduction to Template-Driven Forms
Template-driven forms use directives in your HTML template to create forms. Angular automatically creates FormControl
instances for each form element using ngModel
. These forms are simpler to implement than reactive forms but offer less fine-grained control.
Key features:
- Simplicity and ease of use.
- Two-way data binding with
ngModel
. - Basic form validation built into the template.
- Suitable for small-scale applications.
2. Setting Up Angular Forms Module
Before creating template-driven forms, import FormsModule
in your app.module.ts
:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
FormsModule
provides directives likengForm
,ngModel
, and validation tools.- Without importing
FormsModule
, template-driven forms won’t work.
3. Basic Template-Driven Form Example
A simple form example:
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
<input name="username" ngModel required />
<button type="submit">Submit</button>
</form>
#userForm="ngForm"
assigns the form to a template reference variable.(ngSubmit)
triggers theonSubmit()
method in the component.ngModel
binds the input field to the component data.required
adds basic validation.
4. Two-Way Data Binding with ngModel
ngModel
enables two-way data binding between form inputs and component properties:
import { Component } from '@angular/core';
@Component({
selector: 'app-user-form',
template: `
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
<input name="username" [(ngModel)]="user.username" required />
<button type="submit">Submit</button>
</form>
<p>Your input: {{ user.username }}</p>
`
})
export class UserFormComponent {
user = { username: '' };
onSubmit(form: any) {
console.log('Form Submitted', form.value);
}
}
[(ngModel)]
binds the input field touser.username
.- Changes in the input are reflected in the component and vice versa.
5. Form Submission
Template-driven forms submit data through (ngSubmit)
:
onSubmit(form: NgForm) {
if (form.valid) {
console.log('Form Data:', form.value);
} else {
console.log('Form is invalid');
}
}
NgForm
provides properties likevalid
,invalid
,value
,controls
, andstatus
.- Use these properties to manage form submissions safely.
6. Built-in Validations
Angular provides several built-in validators:
required
– ensures the field is not empty.minlength
/maxlength
– sets character limits.pattern
– applies regex validation.email
– checks for valid email format.
Example:
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
<input name="email" ngModel required email />
<input name="password" ngModel required minlength="6" />
<button type="submit">Submit</button>
</form>
7. Displaying Validation Messages
Show feedback when users enter invalid data:
<input name="email" ngModel required email #email="ngModel" />
<div *ngIf="email.invalid && email.touched">
<small *ngIf="email.errors?.required">Email is required</small>
<small *ngIf="email.errors?.email">Enter a valid email</small>
</div>
- Use
#email="ngModel"
to reference the input’s validation status. touched
ensures messages appear only after user interaction.
8. Accessing Form Values and Status
You can access the form’s values and status directly in the component:
onSubmit(form: NgForm) {
console.log('Form Values:', form.value);
console.log('Form Valid:', form.valid);
console.log('Form Controls:', form.controls);
}
form.value
– returns an object with all form field values.form.controls
– returnsFormControl
objects for each input.
9. Resetting and Prefilling Forms
Reset form values after submission:
onSubmit(form: NgForm) {
console.log('Form Submitted', form.value);
form.reset();
}
Prefill form fields using the component model:
user = { username: 'JohnDoe', email: '[email protected]' };
- Inputs automatically display the initial values via
ngModel
.
10. Handling Nested Forms
Template-driven forms can have nested groups using <ngModelGroup>
:
<form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
<div ngModelGroup="address">
<input name="street" ngModel required placeholder="Street" />
<input name="city" ngModel required placeholder="City" />
</div>
<button type="submit">Submit</button>
</form>
- Nested forms help organize complex forms logically.
- Access nested values with
form.value.address.street
.
11. Dynamic Form Controls
You can dynamically show/hide inputs:
<input type="checkbox" [(ngModel)]="showPhone" /> Add phone number
<div *ngIf="showPhone">
<input name="phone" ngModel pattern="[0-9]{10}" />
</div>
- Conditional controls appear only when needed.
- Validators apply only if the control exists in the DOM.
12. Custom Validation
You can define custom validators using functions:
import { NgModel } from '@angular/forms';
validateUsername(control: NgModel) {
const value = control.value;
if (value && value.includes('admin')) {
return { forbiddenName: true };
}
return null;
}
Use it in the template:
<input name="username" ngModel #username="ngModel" [ngModelOptions]="{ updateOn: 'blur' }" (ngModelChange)="validateUsername(username)" />
<div *ngIf="username.errors?.forbiddenName">Username cannot contain "admin"</div>
13. Form Events
Template-driven forms emit events such as:
(ngSubmit)
– triggers on form submission.(ngModelChange)
– triggers on input value change.(blur)
– triggers when the input loses focus.
Example:
<input name="username" ngModel (ngModelChange)="onChange($event)" />
14. Real-World Example: User Registration Form
<form #regForm="ngForm" (ngSubmit)="onRegister(regForm)">
<input name="username" ngModel required minlength="3" placeholder="Username" />
<input name="email" ngModel required email placeholder="Email" />
<input name="password" ngModel required minlength="6" type="password" placeholder="Password" />
<button type="submit">Register</button>
</form>
Component:
user = { username: '', email: '', password: '' };
onRegister(form: NgForm) {
if (form.valid) {
console.log('User Registered', form.value);
form.reset();
}
}
- Covers multiple inputs, validations, and submission handling.
15. Best Practices for Template-Driven Forms
- Use
ngModel
for simple forms. - Prefer reactive forms for complex logic.
- Always provide
name
attributes for inputs. - Use template reference variables to display validation messages.
- Keep validations in the template for readability.
- Reset or prefill forms via the component model.
- Group related inputs using
ngModelGroup
.
16. Common Pitfalls and How to Avoid Them
- Forgetting to import
FormsModule
. - Missing
name
attribute on inputs. - Using reactive-only features in template-driven forms.
- Not handling form reset correctly.
- Ignoring form validity before submission.
Leave a Reply