| معيار الإدخال البرمجي | الأسلوب التقليدي (Decorator @Input) | الأسلوب الحديث المعتمد على الإشارات (input API) |
|---|---|---|
| طريقة التعريف في صنف المكون | @Input() propertyName: string = ''; | propertyName = input<string>('defaultValue'); أو input.required<string>(); |
| كيفية قراءة القيمة داخل المكون | استدعاء اسم المتغير مباشرة كخاصية (this.propertyName) | استدعاء المتغير كدالة تفاعلية (this.propertyName()) |
| إدارة القيم الافتراضية والنوعية | تعتمد على القيم الابتدائية التقليدية وتفتقر للصرامة أحياناً | دعم كامل للأنواع وإلزامية التحديد عبر input.required بكل أمان هندسي |
| التكامل مع نظام Signals والإشارات | تتطلب ربطاً إضافياً أو مراقبة عبر ngOnChanges | متوافقة كلياً وبشكل تلقائي مع الإشارات المحسوبة والتأثيرات |
صل في هذا الدرس الخامس من الفصل السادس إلى إحدى أهم ركائز بناء العمارة البرمجية في أنجولر، ألا وهي ربط البيانات مع المكونات الفرعية باستخدام الخصائص (Component Inputs) في إصدار Angular 22.1. تتيح لك هذه الميزة تمرير البيانات بسلاسة وأمان من المكون الأب إلى المكونات الفرعية التابعة له. وفي الإصدارات الحديثة، أصبحت الخصائص تُعرف كإشارات (signals-based inputs)، مما يمنحها قوة تفاعلية فائقة وسرعة مذهلة في الاستجابة للتغيرات.
في الهندسة الحديثة لأنجولر، يمكنك إلزام المكون الأب بتمرير بيانات محددة للمكون الفرعي عبر استخدام دالة input.required<T>(). إذا نسي المطور تمرير هذه البيانات، سيُظهر مترجم الكود خطأ فوري أثناء مرحلة البناء، مما يمنع الأخطاء غير المتوقعة في واجهة المستخدم.
بما أن الـ input الجديد يُعاد بناءه كإشارة (Signal)، فإنه يمكنك تمريره مباشرة داخل الدوال المحسوبة (computed) أو التأثيرات (effects) لإنشاء مسارات بيانات تفاعلية ونقية تتحدث لحظياً فور وصول أي قيمة جديدة من الأب.
| 1 | import { Component, input } from '@angular/core'; |
| 2 | |
| 3 | @Component({ |
| 4 | selector: 'app-user-badge', |
| 5 | standalone: true, |
| 6 | template: ` |
| 7 | <div class="badge-card"> |
| 8 | <h4>بطاقة المستخدم الفرعية</h4> |
| 9 | <!-- قراءة قيمة الـ input الحديثة كدالة --> |
| 10 | <p>اسم المستخدم: <strong>{{ userName() }}</strong></p> |
| 11 | <p>رقم العضوية: <strong>{{ memberId() }}</strong></p> |
| 12 | </div> |
| 13 | ` |
| 14 | }) |
| 15 | export class UserBadgeComponent { |
| 16 | // تعريف إدخال اختياري بقيمة افتراضية |
| 17 | userName = input<string>('مزارع مجهول'); |
| 18 | |
| 19 | // تعريف إدخال إلزامي لا يمكن تخطيه من المكون الأب |
| 20 | memberId = input.required<number>(); |
| 21 | } |
| 1 | import { Component, signal } from '@angular/core'; |
| 2 | import { UserBadgeComponent } from './user-badge.component'; |
| 3 | |
| 4 | @Component({ |
| 5 | selector: 'app-parent-dashboard', |
| 6 | standalone: true, |
| 7 | imports: [UserBadgeComponent], |
| 8 | template: ` |
| 9 | <div class="dashboard-box"> |
| 10 | <h3>لوحة التحكم الرئيسية للأب</h3> |
| 11 | |
| 12 | <!-- تمرير البيانات للمكون الفرعي بأمان --> |
| 13 | <app-user-badge |
| 14 | [userName]="currentUser()" |
| 15 | [memberId]="currentId()"> |
| 16 | </app-user-badge> |
| 17 | |
| 18 | <button (click)="changeUserData()">تغيير بيانات المستخدم</button> |
| 19 | </div> |
| 20 | ` |
| 21 | }) |
| 22 | export class ParentDashboardComponent { |
| 23 | currentUser = signal('أحمد مطر'); |
| 24 | currentId = signal(5042); |
| 25 | |
| 26 | changeUserData() { |
| 27 | this.currentUser.set('سارة المهندس'); |
| 28 | this.currentId.set(9981); |
| 29 | } |
| 30 | } |