| مستوى التقسيم المعماري | الأسلوب البرمجي في أنگولر | الأثر الهندسي على الصيانة والأداء |
|---|---|---|
| التجزئة الداخلية للمجموعات | استخدام `FormGroup` فرعية داخل نفس الصنف (مثل `personalInfo` و `shippingInfo`) | تنظيم كائن البيانات برمجياً وفصل قواعد التحقق لكل مقطع على حدة |
| التجزئة إلى مكونات مستقلة | توزيع حقول النموذج على مكونات فرعية مصغرة مدعومة بـ `ControlValueAccessor` | إعادة استخدام أجزاء النموذج في أماكن متعددة وتخفيف الحمل البرمجي عن المكون الرئيسي |
| التحقق والتدقيق المعزول | فحص صلاحية كل وحدة فرعية على حدة (`subForm.get('section')?.valid`) | منع تداخل أخطاء الحقول وتسهيل تتبع المشاكل برمجياً في الأجزاء المعقدة |
يُعتبر التعامل مع النماذج الضخمة التي تحتوي على عشرات الحقول داخل مكوّن واحد خطأً معمارياً جسيماً يؤدي إلى تداخل البيانات وصعوبة الصيانة. يعتمد مبدأ فصل وتصنيف النماذج الكبيرة إلى وحدات وفرعيات مصغرة (Decomposing Large Forms) على تقسيم النموذج الأكبر إلى FormGroups فرعية مستقلة، أو توزيعها على مكونات فرعية مصغرة تتواصل بسلاسة لضمان هيكل برمجي نظيف وقابل للتوسع.
بدلاً من إنشاء نموذج مسطح (Flat Form) يحتوي على حقول كثيرة، يتم بناء شجرة نماذج هرمية تتكون من مجموعات فرعية، مما يجعل استخراج البيانات وإرسالها للخادم يطابق تماماً هيكل البيانات المطلوب في الـ Backend.
فصل أجزاء النموذج يتيح لك تفعيل أو تعطيل مجموعات كاملة من الحقول ديناميكياً (مثل إخفاء وإظهار تفاصيل الدفع بناءً على اختيار طريقة الدفع) دون كسر باقي بنية النموذج.
| 1 | import { Component } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-decomposed-form', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule, ReactiveFormsModule], |
| 9 | template: ` |
| 10 | <div class="decomposed-card-demo"> |
| 11 | <h3>نموذج هيكلي مقسم إلى وحدات فرعية</h3> |
| 12 | |
| 13 | <form [formGroup]="masterForm" (ngSubmit)="onMasterSubmit()"> |
| 14 | |
| 15 | <!-- الوحدة الفرعية الأولى: البيانات الشخصية --> |
| 16 | <div formGroupName="personal" class="form-section-box"> |
| 17 | <h4>أولاً: البيانات الشخصية الأساسية</h4> |
| 18 | <div class="input-row"> |
| 19 | <input type="text" formControlName="fullName" placeholder="الاسم الكامل..." class="styled-input" /> |
| 20 | <input type="email" formControlName="email" placeholder="البريد الإلكتروني..." class="styled-input" /> |
| 21 | </div> |
| 22 | </div> |
| 23 | |
| 24 | <!-- الوحدة الفرعية الثانية: عنوان الشحن والتوصيل --> |
| 25 | <div formGroupName="address" class="form-section-box"> |
| 26 | <h4>ثانياً: تفاصيل عنوان الشحن</h4> |
| 27 | <div class="input-row"> |
| 28 | <input type="text" formControlName="city" placeholder="المدينة..." class="styled-input" /> |
| 29 | <input type="text" formControlName="postalCode" placeholder="الرمز البريدي..." class="styled-input" /> |
| 30 | </div> |
| 31 | </div> |
| 32 | |
| 33 | <!-- زر الإرسال المشروط بصلاحية الهيكل بالكامل --> |
| 34 | <button type="submit" [disabled]="masterForm.invalid" class="submit-action-btn"> |
| 35 | إعتماد وإرسال النموذج الهيكلي المتكامل |
| 36 | </button> |
| 37 | </form> |
| 38 | </div> |
| 39 | `, |
| 40 | styles: [` |
| 41 | .decomposed-card-demo { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; border: 1px solid #1e293b; } |
| 42 | .form-section-box { background: #1e293b; border: 1px solid #334155; padding: 16px; border-radius: 8px; margin-bottom: 16px; } |
| 43 | .form-section-box h4 { margin-top: 0; color: #38bdf8; font-size: 14px; margin-bottom: 12px; } |
| 44 | .input-row { display: flex; gap: 12px; flex-wrap: wrap; } |
| 45 | .styled-input { background: #090d16; border: 1px solid #475569; padding: 10px; border-radius: 6px; color: #fff; flex: 1; min-width: 200px; } |
| 46 | .submit-action-btn { background: #10b981; color: #090d16; border: none; padding: 12px 20px; border-radius: 6px; font-weight: bold; cursor: pointer; width: 100%; margin-top: 10px; } |
| 47 | .submit-action-btn:disabled { background: #475569; cursor: not-allowed; color: #94a3b8; } |
| 48 | `] |
| 49 | }) |
| 50 | export class DecomposedFormComponent { |
| 51 | masterForm: FormGroup; |
| 52 | |
| 53 | constructor(private fb: FormBuilder) { |
| 54 | // بناء نموذج هرمي مقسم إلى مجموعات فرعية لتسهيل الإدارة والصيانة |
| 55 | this.masterForm = this.fb.group({ |
| 56 | personal: this.fb.group({ |
| 57 | fullName: ['', Validators.required], |
| 58 | email: ['', [Validators.required, Validators.email]] |
| 59 | }), |
| 60 | address: this.fb.group({ |
| 61 | city: ['', Validators.required], |
| 62 | postalCode: ['', Validators.required] |
| 63 | }) |
| 64 | }); |
| 65 | } |
| 66 | |
| 67 | onMasterSubmit() { |
| 68 | if (this.masterForm.valid) { |
| 69 | console.log('بيانات النموذج المركب بالكامل:', this.masterForm.value); |
| 70 | } |
| 71 | } |
| 72 | } |
⚠️ تحذير
تجنب ربط المكونات ببعضها بطريقة عشوائية دون هيكل موحد! التجزئة يجب أن تكون مدروسة وتطابق بنية البيانات المتوقعة في الخادم، لتفادي عمليات تحويل البيانات المعقدة (Data Mapping) عند إرسالها للـ Backend.