Reactive Forms
Level: Intermediate
ℹ️ What You'll Learn
- FormControl, FormGroup, FormBuilder
- Validation in code
- Dynamic form controls
- Custom validators
- Form value and status changes
FormBuilder
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
export class StudentFormComponent implements OnInit {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
name: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
className: ['10', Validators.required]
});
}
ngOnInit() {
// Watch for changes
this.form.valueChanges.subscribe(value => {
console.log('Form value:', value);
});
}
onSubmit() {
if (this.form.valid) {
console.log(this.form.value);
}
}
}
FormBuilder shortcuts form creation.
Template
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div>
<label>Name:</label>
<input
type="text"
formControlName="name"
>
<span *ngIf="form.get('name')?.hasError('required') && form.get('name')?.touched">
Name required
</span>
</div>
<div>
<label>Email:</label>
<input
type="email"
formControlName="email"
>
<span *ngIf="form.get('email')?.hasError('email')">
Invalid email
</span>
</div>
<select formControlName="className">
<option value="10">10</option>
<option value="11">11</option>
</select>
<button type="submit" [disabled]="form.invalid">
Submit
</button>
</form>
[formGroup]="form" = bind to form.
formControlName="name" = bind to control.
Validators
form = this.fb.group({
name: ['', Validators.required],
rollNumber: ['', [Validators.required, Validators.pattern(/^[0-9]+$/)]],
email: ['', [Validators.required, Validators.email]],
className: ['', Validators.required]
});
Built-in validators:
required= not emptyminLength(n)= min lengthmaxLength(n)= max lengthemail= valid emailpattern(regex)= regex match
Custom Validators
function uniqueRollNumber(control: AbstractControl) {
if (!control.value) return null;
// Check if roll number exists
return control.value === '101'
? { uniqueRollNumber: true }
: null;
}
form = this.fb.group({
rollNumber: ['', [Validators.required, uniqueRollNumber]]
});
Return null if valid, error object if invalid.
Dynamic Forms
addSubject() {
const subjects = this.form.get('subjects') as FormArray;
subjects.push(this.fb.control('', Validators.required));
}
removeSubject(index: number) {
const subjects = this.form.get('subjects') as FormArray;
subjects.removeAt(index);
}
form = this.fb.group({
name: ['', Validators.required],
subjects: this.fb.array([
this.fb.control('', Validators.required)
])
});
FormArray = dynamic list of controls.
SMS Form
form = this.fb.group({
rollNumber: ['', [
Validators.required,
Validators.pattern(/^[0-9]{3,}$/)
]],
name: ['', [
Validators.required,
Validators.minLength(3)
]],
email: ['', [
Validators.required,
Validators.email
]],
className: ['10', Validators.required],
parentPhone: ['', [
Validators.required,
Validators.pattern(/^[0-9]{10}$/)
]]
});
onSubmit() {
if (this.form.valid) {
this.studentService.createStudent(this.form.value)
.subscribe(() => alert('Student registered!'));
}
}
Form Value and Status
console.log(form.value); // Form values
console.log(form.status); // VALID or INVALID
console.log(form.get('name')?.value); // Single control value
console.log(form.get('name')?.valid); // Single control valid
form.valueChanges.subscribe(value => {
console.log('Form changed:', value);
});
form.statusChanges.subscribe(status => {
console.log('Status:', status);
});
Key Takeaways
- FormBuilder = create forms programmatically
- FormControl = single input
- FormGroup = group of controls
- FormArray = dynamic list
- Validators = built-in validation
- Custom validators = custom logic
- valueChanges = react to changes
💡 Backend Developer Tip
Reactive forms more powerful for complex forms. Use Template-driven for simple, Reactive for complex.
⚠️ Reactive Form Issues
- Forgetting ReactiveFormsModule — formGroup not available
- Using form.name instead of form.get('name') — Wrong access
- Not handling null from get() — Null pointer errors
- Validators in wrong place — Must be in FormBuilder
🤖Use AI to Learn Faster
Use ChatGPT, Claude, or Copilot to go deeper on Reactive Forms. Try these prompts:
"When use Reactive vs Template-driven forms?""How do you add dynamic form controls?""What's difference between value and status?""Quiz me on FormBuilder"
💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.
nexcoding.in
Have questions on your tech stack, ongoing projects, or need one-to-one training?