| نمط توزيع الحالة داخل الخدمة | طريقة تخزين البيانات وبرمجتها | السيناريو الهندسي الأمثل للاستخدام |
|---|---|---|
| حالة محلية خاصة داخل الخدمة (Private Mutable State) | استخدام إشارات خاصة داخل الخدمة مع توفير واجهة قراءة فقط (Readonly) للخارج | حماية البيانات من التعديلات العشوائية وضمان مرور التحديثات عبر قنوات آمنة |
| الحالة المشتركة المفتوحة (Public Shared State) | السماح للمكونات الخارجية بتعديل الإشارات مباشرة دون قيود | التطبيقات الصغيرة جداً أو نماذج الاختبار السريعة التي لا تتطلب حماية معمارية صارمة |
| الحالة المشتقة والمحسوبة (Computed State) | الاعتماد على وظائف `computed()` داخل الخدمة لتوليد بيانات جديدة تلقائياً بناءً على التغيرات | تحديث إحصائيات النظام والعدّادات اللحظية فور حدوث أي تغيير في القائمة الأصلية |
حين لا يحتاج مشروعك البرمجي إلى مكتبات إدارة حالة ضخمة ومعقدة، توفر لك بيئة Angular 22.1 حلاً معمارياً رشيقاً ومثالياً عبر توظيف الخدمات (Services) كأداة خفيفة لإدارة الحالة المركزية (Lightweight State Management). هذا النمط يتيح للمطورين مركزية البيانات ومشاركتها بسلاسة بين المكونات المستقلة دون إضافات برمجية زائدة، مع الحفاظ على كود نظيف وسهل الصيانة.
عند تسجيل الخدمة بنطاق الجذور، فإنها تضمن بقاء حالة البيانات محفوظة وموحدة طوال فترة تشغيل التطبيق. أي مكون يقوم بحقن هذه الخدمة سيحصل مباشرة على نفس النسخة من الحالة والبيانات المحدثة لحظياً.
من خلال تخزين البيانات داخل Signals داخل الخدمة، يتحول الكلاس العادي إلى محرك تفاعلي يرسل التحديثات تلقائياً إلى كافة واجهات المستخدم المرتبطة بها دون الحاجة لاشتراكات مانیوال أو تعقيدات برمجية.
| 1 | import { Injectable, signal, computed } from '@angular/core'; |
| 2 | |
| 3 | export interface TaskItem { |
| 4 | id: number; |
| 5 | title: string; |
| 6 | isCompleted: boolean; |
| 7 | } |
| 8 | |
| 9 | @Injectable({ |
| 10 | providedIn: 'root' |
| 11 | }) |
| 12 | export class TaskService { |
| 13 | private tasksSignal = signal<TaskItem[]>([ |
| 14 | { id: 1, title: 'تصميم هيكل التطبيق المعماري', isCompleted: true }, |
| 15 | { id: 2, title: 'تطبيق أنظمة الإشارات الحديثة', isCompleted: false } |
| 16 | ]); |
| 17 | |
| 18 | readonly tasks = this.tasksSignal.asReadonly(); |
| 19 | |
| 20 | readonly pendingTasksCount = computed(() => |
| 21 | this.tasksSignal().filter(t => !t.isCompleted).length |
| 22 | ); |
| 23 | |
| 24 | toggleTaskStatus(id: number) { |
| 25 | this.tasksSignal.update(list => |
| 26 | list.map(task => task.id === id ? { ...task, isCompleted: !task.isCompleted } : task) |
| 27 | ); |
| 28 | } |
| 29 | } |
| 1 | import { Component, inject } from '@angular/core'; |
| 2 | import { CommonModule } from '@angular/common'; |
| 3 | import { TaskService } from './task.service'; |
| 4 | |
| 5 | @Component({ |
| 6 | selector: 'app-task-manager', |
| 7 | standalone: true, |
| 8 | imports: [CommonModule], |
| 9 | template: ` |
| 10 | <div class="panel-box"> |
| 11 | <h3>إدارة المهام عبر الخدمات الخفيفة</h3> |
| 12 | <p>المهام المعلقة التي تتطلب إنجازاً: <strong>{{ taskService.pendingTasksCount() }}</strong></p> |
| 13 | |
| 14 | <ul class="task-list"> |
| 15 | @for (task of taskService.tasks(); track task.id) { |
| 16 | <li class="task-item" (click)="taskService.toggleTaskStatus(task.id)"> |
| 17 | <span [class.completed]="task.isCompleted">{{ task.title }}</span> |
| 18 | <span class="badge">{{ task.isCompleted ? 'منجز' : 'قيد العمل' }}</span> |
| 19 | </li> |
| 20 | } |
| 21 | </ul> |
| 22 | </div> |
| 23 | `, |
| 24 | styles: [` |
| 25 | .panel-box { background: #0f172a; color: #fff; padding: 20px; border-radius: 10px; border: 1px solid #334155; } |
| 26 | .task-list { list-style: none; padding: 0; margin-top: 12px; } |
| 27 | .task-item { display: flex; justify-content: space-between; background: #1e293b; padding: 10px 14px; margin-bottom: 8px; border-radius: 6px; cursor: pointer; } |
| 28 | .completed { text-decoration: line-through; color: #94a3b8; } |
| 29 | .badge { background: #38bdf8; color: #0f172a; padding: 2px 8px; border-radius: 4px; font-size: 12px; font-weight: bold; } |
| 30 | `] |
| 31 | }) |
| 32 | export class TaskManagerComponent { |
| 33 | readonly taskService = inject(TaskService); |
| 34 | } |