📝 لماذا النماذج (Forms) مهمة في Angular؟
النماذج هي البوابة الرئيسية للتفاعل بين المستخدم والتطبيق. سواء كان تسجيل دخول، إنشاء حساب، إضافة منتج، أو إرسال رسالة - كلها بتعتمد على نماذج. Angular بتقدم حلين قويين للتعامل مع النماذج: Template-driven Forms للنماذج البسيطة، و Reactive Forms للنماذج المعقدة.
الفرق الجوهري: في Template-driven، المنطق بيكون في الـ Template (HTML). في Reactive، المنطق بيكون في الـ Component (TypeScript). ده بيخلي Reactive Forms أكثر قوة، مرونة، وسهولة في الاختبار.
بنهاية هذا الدرس، هتكون قادر على:
- بناء نماذج بسيطة باستخدام Template-driven Forms
- بناء نماذج معقدة باستخدام Reactive Forms و FormBuilder
- إضافة التحقق من الصحة (Validation) للحقول
- عرض رسائل خطأ واضحة للمستخدم
- اختيار النوع المناسب حسب احتياجات المشروع
🎯 Template-driven Forms - النماذج المبنية على القالب
Template-driven Forms هي الطريقة الأسهل والأسرع. بتعتمد على Directives في HTML (زي ngModel و ngForm) وبتستخدم Two-way Data Binding. المنطق كله في الـ Template، والـ Component بس بيستقبل البيانات النهائية.
🔍 الخطوة 1: إعداد FormsModule
🔍 الخطوة 2: بناء النموذج في Template
🔍 الخطوة 3: معالجة الإرسال في Component
pristine= الحقل لسه متعدلش (قيمته الأصلية)dirty= الحقل اتعدل (المستخدم كتب فيه)touched= الحقل اكتسب Focus وخرج منه (blur)untouched= الحقل لسه ما اكتسبش Focusvalid= الحقل يمر كل الـ Validatorsinvalid= الحقل فشل في Validator واحد على الأقل
⚡ Reactive Forms - النماذج التفاعلية (مستحسن)
Reactive Forms هي الطريقة الأقوى والأكثر مرونة. بتعتمد على FormBuilder و FormGroup و FormControl في الـ Component. المنطق كله في TypeScript، والـ Template بس بيربط بالـ Controls.
المميزات: اختبار أسهل (تقدر تختبر النموذج من غير DOM)، منطق أكثر تعقيد (Dynamic Fields, Nested Forms)، و أداء أفضل (Change Detection محسّن).
🔍 الخطوة 1: إعداد ReactiveFormsModule
🔍 الخطوة 2: بناء النموذج برمجياً
🔍 الخطوة 3: ربط النموذج في Template
🔍 مقارنة شاملة: Template-driven vs Reactive Forms
| الجانب | Template-driven | Reactive |
|---|---|---|
| الصعوبة | ⭐ أسهل - Directives في HTML | ⭐⭐ أصعب - منطق في TypeScript |
| المرونة | محدودة - Validators جاهزة بس | عالية جداً - Validators مخصصة، Dynamic Fields |
| الاختبار | صعب - محتاج DOM | سهل - تختبر من غير DOM |
| النماذج المعقدة | ❌ غير مناسب | ✅ مناسب جداً (Nested, Arrays) |
| Two-way Binding | ✅ تلقائي مع ngModel | ❌ يدوي (valueChanges) |
| الأداء | أقل - Change Detection على كل حقل | أفضل - Change Detection محسّن |
| متى تستخدم؟ | نماذج بسيطة (Contact, Search) | نماذج معقدة (Register, Checkout) |
✅ Validators المدمجة في Angular
Angular بتوفّر مجموعة من Validators الجاهزة للتحقق من صحة البيانات:
| الـ Validator | الاستخدام | مثال |
|---|---|---|
required |
الحقل مطلوب (مش فارغ) | Validators.required |
minLength(n) |
الحد الأدنى للأحرف | Validators.minLength(3) |
maxLength(n) |
الحد الأقصى للأحرف | Validators.maxLength(50) |
email |
بريد إلكتروني صحيح | Validators.email |
pattern(regex) |
يطابق Regular Expression | Validators.pattern('^[0-9]+$') |
min(n) / max(n) |
للأرقام | Validators.min(18) |
⚠️ أخطاء شائعة في Angular Forms وتجنبها
❌ الخطأ 1: نسيان استيراد FormsModule أو ReactiveFormsModule
المشكلة: ngModel أو formGroup مش بيشتغلوا وبتطلع أخطاء في Console.
الحل: تأكد إنك مستورد FormsModule (لـ Template-driven) أو ReactiveFormsModule (لـ Reactive) في app.module.ts.
❌ الخطأ 2: استخدام ngModel مع formControlName في نفس الحقل
المشكلة: Angular بتطلع تحذير وبيحصل conflict.
الحل: استخدم ngModel في Template-driven، و formControlName في Reactive. متخلطش بينهم.
❌ الخطأ 3: عدم التحقق من form.invalid قبل الإرسال
المشكلة: بيانات غير صالحة بتتبعت للـ API.
الحل: دايماً افحص if (form.valid) أو if (this.loginForm.invalid) return; قبل ما تبعت البيانات.
💡 معايير احترافية في Angular Forms
- استخدم Reactive Forms للنماذج المعقدة: Registration, Checkout, Wizard Forms.
- استخدم Template-driven للنماذج البسيطة: Contact, Newsletter, Search.
- تحقق من الأخطاء باستخدام Validators: متعتمدش على HTML validation بس.
- أظهر رسائل الخطأ بوضوح: قول للمستخدم بالظبط إيه المشكلة وإزاي يصلحها.
- استخدم formGroup و formControlName في Reactive: متستخدمش ngModel معاهم.
- استخدم Getters للوصول السهل للحقول:
get username() { return this.form.get('username'); } - عطل زر الإرسال لما النموذج غير صالح:
[disabled]="form.invalid". - أضف حالة تحميل (Loading) للزر: عشان المستخدم يعرف إن حاجة بتحصل.
📚 دروس ذات صلة
❓ أسئلة شائعة عن Angular Forms
هل يمكن استخدام Template-driven و Reactive في نفس المشروع؟
نعم، ومش بس كده - في نفس الـ Module كمان! تقدر تستورد FormsModule و ReactiveFormsModule مع بعض في app.module.ts. بس في نفس الـ Component، لازم تختار نوع واحد. متستخدمش ngModel و formControlName في نفس الحقل.
إزاي أضيف Validator مخصص في Reactive Forms؟
اعمل دالة ترجع ValidatorFn. مثلاً Validator يتحقق إن الباسورد يحتوي على حرف كبير: passwordValidator(control: AbstractControl): ValidationErrors | null { ... }. وبعدين ضيفه في مصفوفة Validators: [Validators.required, passwordValidator].
هل Angular Forms آمنة ضد XSS؟
Angular بتعمل Sanitization تلقائي للبيانات اللي بتعرضها في Template. لكن لو هتبعت البيانات لـ Backend، لازم تعمل Sanitization على السيرفر كمان. متعتمدش على Client-side validation بس - دايماً تحقق على السيرفر.
إزاي أعمل Dynamic Fields (حقول تضاف/تحذف ديناميكياً)؟
في Reactive Forms، استخدم FormArray. مثلاً لو عندك نموذج بيضيف أرقام تليفون: phones: this.fb.array([this.fb.control('')]). وبعدين تقدر تضيف بـ this.phones.push(this.fb.control('')) وتحذف بـ this.phones.removeAt(index).