| معيار المخرجات البرمجية | الأسلوب التقليدي (Decorator @Output مع EventEmitter) | الأسلوب الحديث المعتمد على دالة output |
|---|---|---|
| طريقة التعريف في صنف المكون | @Output() notify = new EventEmitter<string>(); | notify = output<string>(); |
| طريقة إطلاق الحدث للأعلى | this.notify.emit('رسالة الحدث'); | this.notify('رسالة الحدث'); (الاستدعاء كدالة مباشرة) |
| المرونة ونوع البيانات | يتطلب استيراد فئات متعددة وإدارة صريحة للنوع | أكثر سلاسة، وأقصر كتابة، ومتوافقة كلياً مع الأنظمة الحديثة |
| التكامل الهندسي | النمط الكلاسيكي المدعوم في الإصدارات القديمة | النمط المعياري الموصى به في Angular 22.1 |
هو إرسال البيانات والأحداث للأعلى باستخدام المخرجات (Component Outputs) في إصدار Angular 22.1. بينما تستخدم الخصائص (Inputs) لتمرير البيانات للأسفل، تتيح لك المخرجات (Outputs) إعلام المكون الأب بوقوع أحداث جديدة أو إرسال بيانات نحو الأعلى، مع الاعتماد على الأسلوب الحديث والآمن الذي يتناغم تماماً مع بنية الإشارات (Signals). وكما طلبت في الدرس السابق، سنحافظ على تنوع الأكواد لتشمل قالب الواجهة (HTML) ونمط التنسيق (CSS) بجانب الأكواد البرمجية (TypeScript).
في النسخة الحديثة لأنجولر، لم تعد بحاجة لاستخدام EventEmitter التقليدي بشكل معقد. يمكنك تعريف المخرج بكل بساطة عبر دالة output<T>() وإرسال القيمة مباشرة نحو الأعلى عن طريق استدعاء المخرج كدالة برمجية (this.actionName(value)).
يتيح هذا النمط للمكون الفرعي إرسال البيانات للأعلى بكفاءة تامة، مع الحفاظ على استقلاليته الكاملة وعدم اعتماده على تفاصيل بنية المكون الأب، مما يرفع من جودة إعادة استخدام المكونات (Reusability).
| 1 | import { Component, output } from '@angular/core'; |
| 2 | |
| 3 | @Component({ |
| 4 | selector: 'app-item-editor', |
| 5 | standalone: true, |
| 6 | templateUrl: './item-editor.component.html', |
| 7 | styleUrl: './item-editor.component.css' |
| 8 | }) |
| 9 | export class ItemEditorComponent { |
| 10 | // تعريف مخرج حديث يرسل نصاً للأعلى عند التعديل |
| 11 | itemSaved = output<string>(); |
| 12 | |
| 13 | onSave(newVal: string) { |
| 14 | if (newVal.trim()) { |
| 15 | // إرسال البيانات للأعلى مباشرة عبر استدعاء المخرج كدالة |
| 16 | this.itemSaved(newVal); |
| 17 | } |
| 18 | } |
| 19 | } |
| 1 | <div class="editor-container"> |
| 2 | <h4>تعديل العنصر الفرعي والإرسال للأعلى</h4> |
| 3 | <input #inputField type="text" placeholder="أدخل اسم العنصر الجديد..." /> |
| 4 | <button (click)="onSave(inputField.value)">حفظ وإرسال للأب</button> |
| 5 | </div> |
| 1 | .editor-container { |
| 2 | padding: 16px; |
| 3 | border: 2px dashed #4f46e5; |
| 4 | border-radius: 8px; |
| 5 | background-color: #f9fafb; |
| 6 | margin-top: 12px; |
| 7 | } |
| 8 | |
| 9 | .editor-container input { |
| 10 | padding: 8px; |
| 11 | margin-right: 8px; |
| 12 | border: 1px solid #d1d5db; |
| 13 | border-radius: 4px; |
| 14 | } |
| 15 | |
| 16 | .editor-container button { |
| 17 | padding: 8px 16px; |
| 18 | background-color: #4f46e5; |
| 19 | color: white; |
| 20 | border: none; |
| 21 | border-radius: 4px; |
| 22 | cursor: pointer; |
| 23 | } |
| 1 | import { Component, signal } from '@angular/core'; |
| 2 | import { ItemEditorComponent } from './item-editor.component'; |
| 3 | |
| 4 | @Component({ |
| 5 | selector: 'app-main-dashboard', |
| 6 | standalone: true, |
| 7 | imports: [ItemEditorComponent], |
| 8 | template: ` |
| 9 | <div class="parent-panel"> |
| 10 | <h3>لوحة التحكم الرئيسية</h3> |
| 11 | <p>آخر عنصر تم استقباله من الأسفل: <strong>{{ lastItem() }}</strong></p> |
| 12 | |
| 13 | <!-- الاستماع للحدث القادم من المكون الفرعي --> |
| 14 | <app-item-editor (itemSaved)="handleItemSaved($event)"></app-item-editor> |
| 15 | </div> |
| 16 | ` |
| 17 | }) |
| 18 | export class MainDashboardComponent { |
| 19 | lastItem = signal('لا يوجد عنصر بعد'); |
| 20 | |
| 21 | handleItemSaved(itemValue: string) { |
| 22 | // تحديث الحالة بناءً على البيانات المرسلة من الأسفل |
| 23 | this.lastItem.set(itemValue); |
| 24 | } |
| 25 | } |