| وجه المقارنة المعمارية | توجيهات السمات (Attribute Directives) | التوجيهات الهيكلية (Structural Directives) |
|---|---|---|
| طبيعة التأثير على الـ DOM | تعديل السمات، الخصائص، الأنماط، أو الأصناف لعنصر موجود مسبقاً | إضافة، إزالة، أو تدمير عناصر وقوالب كاملة من شجرة الـ DOM |
| رمز الاستدعاء في القالب | يتم استدعاؤها عبر اسم التوجيه مباشرة كسمة (مثل appDirective) | يتم استدعاؤها مسبوقاً بعلامة النجمة (مثل *appDirective) أو بصيغة البنية المجاورة |
| الاعتماد على حقن الحاويات | تكتفي بحقن `ElementRef` و `Renderer2` للتحكم بالمظهر | تتطلب حقن `TemplateRef` و `ViewContainerRef` لإدارة القوالب |
بناء توجيه هيكلي مخصص (Custom Structural Directive). بعد أن أمضينا الدروس السابقة في استكشاف توجيهات السمات (Attribute Directives) التي تعدل مظهر أو سلوك العناصر الموجودة أصلاً، ننتقل اليوم إلى المستوى الأكثر تقدماً؛ وهو بناء التوجيهات الهيكلية التي تتحكم في إضافة أو إزالة عناصر الـ DOM من جذورها بناءً على شروط برمجية مخصصة (مثل تكرار العناصر أو إظهارها وإخفائها كبدائل متطورة لهياكل التحكم الحديثة).
عندما يضع المطور علامة النجمة * أمام التوجيه الهيكلي (مثل *appIfRole="admin")، فإن أنجولر تقوم تلقائياً بتحويل هذا العنصر إلى قالب مضمن (<ng-template>). يتيح TemplateRef للتوجيه إمكانية قراءة هذا القالب المحجوز والاحتفاظ به في الذاكرة.
هي الحاوية البرمجية المسؤولة عن حقن، إنشاء، أو تدمير القوالب داخل شجرة الـ DOM. يقوم التوجيه الهيكلي باستخدام هذه الحاوية لإضافة القالب (createEmbeddedView) عندما يتحقق الشرط، أو مسحه تماماً (clear) عندما ينتفي الشرط.
| 1 | import { Directive, inject, Input, TemplateRef, ViewContainerRef } from '@angular/core'; |
| 2 | |
| 3 | @Directive({ |
| 4 | selector: '[appAuthorizeRole]', |
| 5 | standalone: true |
| 6 | }) |
| 7 | export class AuthorizeRoleDirective { |
| 8 | private templateRef = inject(TemplateRef<any>); |
| 9 | private viewContainer = inject(ViewContainerRef); |
| 10 | |
| 11 | // محاكاة دور المستخدم الحالي في النظام (يمكن ربطه بخدمة مصادقة حقيقية) |
| 12 | private currentUserRole: string = 'admin'; |
| 13 | |
| 14 | // استقبال الدور المطلوب عبر مدخل يتطابق مع اسم التوجيه |
| 15 | @Input() set appAuthorizeRole(requiredRole: string) { |
| 16 | if (this.currentUserRole === requiredRole) { |
| 17 | // إذا كان الدور متطابقاً، يتم إنشاء العنصر وإظهاره في الـ DOM |
| 18 | this.viewContainer.createEmbeddedView(this.templateRef); |
| 19 | } else { |
| 20 | // إذا لم يكن متطابقاً، يتم تفريغ الحاوية وإزالة العنصر تماماً |
| 21 | this.viewContainer.clear(); |
| 22 | } |
| 23 | } |
| 24 | } |
| 1 | import { Component } from '@angular/core'; |
| 2 | import { AuthorizeRoleDirective } from './authorize-role.directive'; |
| 3 | |
| 4 | @Component({ |
| 5 | selector: 'app-structural-directive-demo', |
| 6 | standalone: true, |
| 7 | imports: [AuthorizeRoleDirective], |
| 8 | template: ` |
| 9 | <div class="master-container"> |
| 10 | <h3>استعراض بناء توجيه هيكلي مخصص في Angular 22.1</h3> |
| 11 | <p>يتم التحكم في ظهور العناصر التالية بناءً على صلاحيات المستخدم الهيكلية:</p> |
| 12 | |
| 13 | <!-- عنصر سيظهر لأن الدور المطابق هو admin --> |
| 14 | <div *appAuthorizeRole="'admin'" class="alert-box success"> |
| 15 | <h4>لوحة التحكم السيادية</h4> |
| 16 | <p>هذا المحتوى الهيكلي لا يظهر إلا للمستخدمين الذين يحملون صلاحية المشرف (Admin).</p> |
| 17 | </div> |
| 18 | |
| 19 | <!-- عنصر لن يظهر لأن الدور المطلوب غير متطابق --> |
| 20 | <div *appAuthorizeRole="'super-guest'" class="alert-box warning"> |
| 21 | <h4>قسم الضيوف المميزين</h4> |
| 22 | <p>لن تتمكن من رؤية هذا النص لأن صلاحيتك الحالية لا تطابق هذا القالب.</p> |
| 23 | </div> |
| 24 | </div> |
| 25 | `, |
| 26 | styles: [` |
| 27 | .master-container { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; } |
| 28 | .alert-box { padding: 16px; border-radius: 8px; margin: 12px 0; font-weight: bold; border: 1px solid #334155; } |
| 29 | .success { background: #064e3b; color: #34d399; border-color: #059669; } |
| 30 | .warning { background: #78350f; color: #fbbf24; border-color: #d97706; } |
| 31 | `] |
| 32 | }) |
| 33 | export class StructuralDirectiveDemoComponent {} |