| العنصر أو الواجهة المعمارية | طبيعة الوجود في الذاكرة | الدور والوظيفة الأساسية في أحدث إصدارات Angular 22.1 |
|---|---|---|
| TemplateRef<T> | خامل وغير نشط (Inert Template) | يمثل قالب HTML محجوزاً داخل ng-template لا يظهر في الـ DOM حتى يُستدعى برمجياً |
| ViewContainerRef | حاوية حية ونشطة (Active View Container) | المسؤول المباشر عن حقن، إنشاء، أو مسح وجهات العرض المضمنة داخل شجرة الـ DOM |
| ng-container | عنصر افتراضي هيكلي خفيف | يُستخدم كمنطقة ربط (Anchor) بدون إضافة عناصر وهمية لعرض الـ DOM |
عندما تتطلب المعمارية البرمجية بناء مكونات متطورة مثل النوافذ المنبثقة (Modals)، القوائم المنسدلة الذكية، أو محركات عرض المحتوى المرن في وقت التشغيل (Runtime)، فإن الأسلوب التقليدي يعجز عن تلبية الاحتياجات. هنا يبرز الدور الحيوي للتكامل بين TemplateRef و ViewContainerRef للتحكم الكامل في إنشاء وتدمير القوالب برمجياً.
عندما تضع كوداً داخل وسوم <ng-template>, فإن أنجولر تحوله إلى قالب جاهز للاستخدام لكنها لا تعرضه بصرياً. يمنحك TemplateRef القدرة على الإشارة لهذا القالب والاحتفاظ به كمرجع برمجي آمن.
عبر حقن ViewContainerRef, يمكنك استخدام دوال مثل createEmbeddedView() لزرع القالب في أي مكان تختاره، أو استخدام clear() لتنظيف الحاوية بالكامل ومنع تسرب الذاكرة.
| 1 | import { Component, TemplateRef, ViewChild, ViewContainerRef, AfterViewInit } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | |
| 4 | @Component({ |
| 5 | selector: 'app-dynamic-engine-demo', |
| 6 | standalone: true, |
| 7 | imports: [CommonModule], |
| 8 | template: ` |
| 9 | <div class="engine-wrapper"> |
| 10 | <h3>محرك القوالب الديناميكية (TemplateRef & ViewContainerRef)</h3> |
| 11 | |
| 12 | <div class="controls"> |
| 13 | <button (click)="loadTemplate(successTpl)">عرض قالب النجاح</button> |
| 14 | <button (click)="loadTemplate(errorTpl)">عرض قالب الخطأ</button> |
| 15 | <button (click)="clearContainer()">إفراغ الحاوية</button> |
| 16 | </div> |
| 17 | |
| 18 | <!-- الحاوية المستهدفة لحقن القوالب ديناميكياً --> |
| 19 | <div class="dynamic-host-target"> |
| 20 | <ng-container #dynamicTarget></ng-container> |
| 21 | </div> |
| 22 | |
| 23 | <!-- تعريف القوالب الخامدة (Templates) غير المرئية افتراضياً --> |
| 24 | <ng-template #successTpl> |
| 25 | <div class="card success-card"> |
| 26 | <h4>عملية ناجحة!</h4> |
| 27 | <p>تم حقن هذا القالب ديناميكياً عبر ViewContainerRef بنجاح تام.</p> |
| 28 | </div> |
| 29 | </ng-template> |
| 30 | |
| 31 | <ng-template #errorTpl> |
| 32 | <div class="card error-card"> |
| 33 | <h4>تنبيه خطأ!</h4> |
| 34 | <p>تم تبديل القالب الفوري واستبداله بقالب الخطأ بكفاءة عالية في Angular 22.1.</p> |
| 35 | </div> |
| 36 | </ng-template> |
| 37 | </div> |
| 38 | `, |
| 39 | styles: [` |
| 40 | .engine-wrapper { background: #090d16; color: #fff; padding: 24px; border-radius: 12px; } |
| 41 | .controls { display: flex; gap: 10px; margin-bottom: 16px; } |
| 42 | button { background: #0ea5e9; border: none; padding: 8px 16px; color: #fff; border-radius: 6px; cursor: pointer; font-weight: bold; transition: background 0.2s; } |
| 43 | button:hover { background: #0284c7; } |
| 44 | .dynamic-host-target { margin-top: 16px; border: 2px dashed #334155; padding: 16px; border-radius: 8px; min-height: 80px; } |
| 45 | .card { padding: 14px; border-radius: 6px; font-weight: bold; } |
| 46 | .success-card { background: #064e3b; color: #34d399; border: 1px solid #059669; } |
| 47 | .error-card { background: #78350f; color: #fbbf24; border: 1px solid #d97706; } |
| 48 | `] |
| 49 | }) |
| 50 | export class DynamicEngineDemoComponent implements AfterViewInit { |
| 51 | @ViewChild('dynamicTarget', { read: ViewContainerRef }) container!: ViewContainerRef; |
| 52 | |
| 53 | @ViewChild('successTpl') successTpl!: TemplateRef<any>; |
| 54 | @ViewChild('errorTpl') errorTpl!: TemplateRef<any>; |
| 55 | |
| 56 | ngAfterViewInit() { |
| 57 | this.loadTemplate(this.successTpl); |
| 58 | } |
| 59 | |
| 60 | loadTemplate(template: TemplateRef<any>) { |
| 61 | this.container.clear(); |
| 62 | this.container.createEmbeddedView(template); |
| 63 | } |
| 64 | |
| 65 | clearContainer() { |
| 66 | this.container.clear(); |
| 67 | } |
| 68 | } |