Template-Driven Forms
Template-driven forms rely on directives in the template. ngModel creates FormControls automatically. Less TypeScript, more HTML. Best for simple forms.
Template-driven forms are the simpler alternative to reactive forms. Instead of creating FormControls in TypeScript, you use directives in the template that create the form model automatically.
"Template-driven = HTML pe dependent โ TypeScript mein kam likhna."
How it works:
ngModeldirective on an input creates a FormControl automaticallynameattribute is MANDATORY โ it becomes the control's key in the formngForm(on form element) automatically tracks the entire form state- You access form state via template reference variables like
#myForm="ngForm" - Validation attributes (
required,minlength) work directly in HTML
Template-driven forms are the opposite of reactive forms โ the template drives the logic, not the TypeScript code.
In Angular 17+, template-driven forms use the same provider as reactive forms.
// app.config.ts โ both form types share this provider
import { provideForms } from '@angular/forms';
export const appConfig: ApplicationConfig = {
providers: [
provideForms(), // Enables BOTH reactive AND template-driven forms
]
};
"Same setup as reactive โ Angular 17+ unified both."
Old way (Angular 16 and earlier):
// Old NgModule approach
import { FormsModule } from '@angular/forms';
@NgModule({
imports: [FormsModule], // Template-driven only
})
Now with provideForms(), you get both form types from a single provider. No need to choose between FormsModule and ReactiveFormsModule at import time.
Let's create a template-driven form step by step.
<!-- Component template -->
<form #biryaniForm="ngForm" (ngSubmit)="onSubmit(biryaniForm)">
<!-- name attribute is MANDATORY for ngModel -->
<div class="field">
<label>Biryani Name</label>
<input
name="biryaniName"
ngModel
required
minlength="3"
#name="ngModel"
placeholder="Enter biryani name" />
@if (name.invalid && name.touched) {
<div class="errors">
@if (name.errors?.['required']) {
<small class="error">Name is required</small>
}
@if (name.errors?.['minlength']) {
<small class="error">Min 3 characters</small>
}
</div>
}
</div>
<div class="field">
<label>Category</label>
<select name="category" ngModel required #category="ngModel">
<option value="">Select...</option>
<option value="chicken">Chicken</option>
<option value="mutton">Mutton</option>
</select>
</div>
<button type="submit" [disabled]="biryaniForm.invalid">
Submit
</button>
<!-- Form value preview -->
<pre>{{ biryaniForm.value | json }}</pre>
</form>
"name attribute MANDATORY โ Angular uses it as form control key."
#name="ngModel" creates a template reference that exposes the control's validation state. Without this, you can't access individual field validation in the template.
Component:
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { JsonPipe } from '@angular/common';
@Component({
selector: 'app-template-form',
standalone: true,
imports: [FormsModule, JsonPipe],
templateUrl: './template-form.component.html',
})
export class TemplateFormComponent {
onSubmit(form: NgForm) {
if (form.valid) {
console.log('Form submitted:', form.value);
form.reset();
}
}
}Two-way binding with [(ngModel)] synchronizes the input value and the component property in both directions.
// Component
biryaniName = 'Chicken Dum Biryani';
// Template โ two-way binding
<input [(ngModel)]="biryaniName" name="biryaniName" />
<p>You typed: {{ biryaniName }}</p>
"ngModel = two-way street โ type karo, property update, property change karo, input update."
For FORM fields, use ngModel (without brackets) + name:
<!-- โ
For forms โ registers with ngForm, validation works -->
<input name="email" ngModel required #email="ngModel" />
<!-- โ For forms โ does NOT register with ngForm -->
<input [(ngModel)]="email" name="email" />
Use [(ngModel)] only for simple non-form cases:
// Simple binding outside a form โ works great!
<input [(ngModel)]="searchTerm" (ngModelChange)="onSearch()" />
The key difference: ngModel (without brackets) is one-way from template to form model. [(ngModel)] is two-way between template and component property. Inside a form, prefer ngModel with name.
Template-driven forms are NOT always the right choice. Here's when to use each.
Use Template-Driven when:
- Simple forms with fewer than 5 fields
- Quick prototypes and MVPs
- The form structure is static (no dynamic add/remove)
- Your team prefers HTML-centric approach
- You need a quick contact form, search box, newsletter signup
Use Reactive when:
- Complex forms with 5+ fields
- Dynamic forms (add/remove fields at runtime)
- Custom validators and cross-field validation
- Unit testing forms (reactive forms are pure TypeScript)
- Enterprise applications (TCS, Wipro, Infosys standard)
"Simple form = template-driven, Complex form = reactive."
Rule of thumb: If a form has more than 5 fields or any dynamic behavior, use reactive forms. For simple 2-3 field forms, template-driven is faster to write.
"Hyderabad IT companies = reactive forms mostly."
Key Takeaways
- โ Template-driven: ngModel creates FormControls automatically โ html-centric approach
- โ provideForms() enables BOTH template-driven and reactive forms in Angular 17+
- โ name attribute is MANDATORY โ ngModel won't register with ngForm without it
- โ #ref="ngModel" for validation access, #form="ngForm" for form-level state
- โ Template-driven for simple forms (<5 fields), Reactive for complex/dynamic forms
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login