Reactive Forms ใช้ FormControl เพื่อควบคุม input เดี่ยว ใช้ FormGroup เพื่อรวมหลาย control ใช้ FormArray เพื่อรองรับรายการแบบ dynamic และใช้ Validators เพื่อตรวจสอบความถูกต้องของข้อมูล
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
subgraph Era1["ยุค Manual Validation / Manual Checks"]
A["if input === ''
ตรวจเองทีละ field"]
end
subgraph Era2["ยุค Form Model / Reactive Forms"]
B["FormControl
ควบคุม input"]
C["FormGroup
รวมหลาย field"]
end
subgraph Era3["ยุค Dynamic Validation / Advanced Forms"]
D["FormArray
รายการ dynamic"]
E["Custom/Async Validator
กติกาเฉพาะระบบ"]
end
A --> B --> C --> D --> E
new FormControl('', Validators.required){ name, email }required, minLength, maxLength, email, pattern, min, maxnull เมื่อ valid หรือคืน Object เมื่อ error| ส่วนประกอบ | หน้าที่ | ตัวอย่าง |
|---|---|---|
FormControl |
ควบคุม field เดี่ยว | name |
FormGroup |
รวมหลาย field | profile form |
FormArray |
รายการ dynamic | เบอร์โทรหลายเบอร์ |
FormBuilder |
สร้างฟอร์มแบบสั้น | fb.group() |
Validators |
ตรวจความถูกต้อง | required, email |
%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart TD
A["FormGroup
ฟอร์มหลัก"] --> B["FormControl: name
ชื่อ"]
A --> C["FormControl: email
อีเมล"]
A --> D["FormArray: skills
ทักษะหลายรายการ"]
B --> E["Validators.required
ต้องกรอก"]
C --> F["Validators.email
รูปแบบอีเมล"]
// profile-form.component.ts
// Reactive Form พร้อม built-in validator และ custom validator
import { Component } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, ValidationErrors, Validators } from '@angular/forms';
function noAdminName(control: AbstractControl): ValidationErrors | null {
return control.value?.toLowerCase() === 'admin'
? { reservedName: true }
: null;
}
@Component({
selector: 'app-profile-form',
templateUrl: './profile-form.component.html'
})
export class ProfileFormComponent {
constructor(private fb: FormBuilder) {}
profileForm = this.fb.group({
name: ['', [Validators.required, Validators.minLength(3), noAdminName]],
email: ['', [Validators.required, Validators.email]],
skills: this.fb.array([
this.fb.control('HTML')
])
});
get skills(): FormArray {
return this.profileForm.get('skills') as FormArray;
}
addSkill(): void {
this.skills.push(this.fb.control('', Validators.required));
}
save(): void {
if (this.profileForm.valid) {
console.log(this.profileForm.value);
}
}
}
// ตัวอย่างการใช้งาน:
// กด Add Skill เพื่อเพิ่ม FormControl ใหม่ใน FormArray
<!-- profile-form.component.html -->
<form [formGroup]="profileForm" (ngSubmit)="save()">
<input formControlName="name" placeholder="ชื่อ">
<p *ngIf="profileForm.controls.name.hasError('reservedName')">
ห้ามใช้ชื่อ admin
</p>
<input formControlName="email" placeholder="อีเมล">
<div formArrayName="skills">
<input *ngFor="let skill of skills.controls; let i = index" [formControlName]="i">
</div>
<button type="button" (click)="addSkill()">Add Skill</button>
<button type="submit" [disabled]="profileForm.invalid">Save</button>
</form>
required และ minLengthFormArray สำหรับรายการ keywordtest