تعلّم Angular: دورة مكثفة شاملة للمبتدئين حتى بناء التطبيقات

دقائق القراءة: 10

مقدمة إلى Angular ولماذا يستحق التعلّم

يُعد Angular إطار عمل مجانيًا ومفتوح المصدر لتطوير تطبيقات الويب، وقد طوّرته Google اعتمادًا على TypeScript. ويُستخدم على نطاق واسع لبناء تطبيقات تفاعلية حديثة، خاصة تطبيقات Single Page Applications التي تتطلب أداءً جيدًا، وتنظيمًا واضحًا، وقابلية عالية للتوسع.

إذا كنت تبحث عن مدخل عملي وسريع لفهم أهم مفاهيم Angular، فهذه الدورة المكثفة تمنحك صورة شاملة عن الركائز الأساسية التي تحتاجها للبدء في بناء مشاريعك الخاصة بثقة.

شعار Angular في دورة تعليمية شاملة لتطوير تطبيقات الويب باستخدام TypeScript

تركّز هذه الدورة على استخدام Angular مع TypeScript لفهم المكوّنات الرئيسية في الإطار، بدءًا من Components وحتى Routing وForms وHTTP Client.

ما هو Angular؟

Angular هو إطار عمل موجّه لبناء واجهات المستخدم وتطبيقات الويب والهواتف وسطح المكتب. يعتمد على بنية قائمة على Components، حيث يُقسَّم التطبيق إلى وحدات صغيرة مترابطة ومنظمة على هيئة شجرة من المكوّنات الأبناء والآباء.

تُعرف الإصدارات الحديثة بعد Angular 2 باسم Angular فقط، بينما كان الإصدار الأول يُعرف باسم AngularJS. ومن المهم التمييز بينهما، لأن المعمارية والمفاهيم الأساسية مختلفة بشكل ملحوظ.

لماذا يفضّل كثير من المطورين Angular؟

  • مدعوم رسميًا من Google ويملك مجتمعًا كبيرًا.
  • يعتمد على TypeScript، ما يوفّر كتابة أكثر تنظيمًا وأمانًا.
  • يقدّم نمطًا معماريًا واضحًا يساعد على بناء مشاريع قابلة للصيانة.
  • يتضمن أدوات قوية مثل Routing وDependency Injection وForms وHTTP Client.
  • مناسب للتطبيقات الكبيرة والمعقدة التي تحتاج إلى تنظيم طويل الأمد.

الميزة الأهم هنا أن Angular لا يقدّم مجرد مكتبة صغيرة، بل يقدّم بيئة تطوير متكاملة تساعدك على بناء تطبيقات منظمة وقابلة للاختبار والتوسع.

أهم المحاور التي تغطيها الدورة

المحور الفائدة العملية
Components بناء واجهات مقسّمة إلى أجزاء قابلة لإعادة الاستخدام
Lifecycle Hooks التحكم في سلوك المكوّن أثناء الإنشاء والتحديث والإزالة
Binding ربط البيانات بين TypeScript وواجهة المستخدم
Directives إضافة سلوك ديناميكي لعناصر HTML
Routing التنقل بين الصفحات داخل التطبيق
Forms إنشاء النماذج والتحقق من صحة المدخلات
HTTP Client جلب البيانات من الخوادم والتعامل مع APIs

بنية تطبيق Angular باختصار

يتكوّن تطبيق Angular عادة من مجموعة لبنات أساسية تشمل:

  • Modules لتنظيم أجزاء التطبيق.
  • Components لتمثيل الواجهة والسلوك.
  • Templates لعرض المحتوى.
  • Services لتجميع المنطق القابل لإعادة الاستخدام.
  • Directives لتوسيع سلوك العناصر.
  • Pipes لتنسيق البيانات داخل القوالب.

أي تطبيق Angular يحتوي على الأقل على Root Module، ويُسمى غالبًا AppModule. وفي التطبيقات الأكبر، تُضاف وحدات أخرى لتقسيم الوظائف حسب المجالات أو الخصائص.

Components: حجر الأساس في Angular

تُعد Components الوحدة الأساسية في Angular. كل مكوّن يتكون عادة من:

  • قالب HTML Template يحدد ما سيظهر للمستخدم.
  • فئة TypeScript Class تحتوي على المنطق والبيانات.
  • Selector يحدد طريقة استدعاء المكوّن داخل القوالب.
  • أنماط CSS اختيارية خاصة بالمكوّن.

الهدف من استخدام المكوّنات هو تجزئة الواجهة إلى أجزاء أصغر وأكثر تنظيمًا، مما يسهل إعادة الاستخدام والاختبار والصيانة.

إنشاء مكوّن جديد يدويًا

رغم أن Angular CLI هو الأسهل لإنشاء المكوّنات، فإن فهم الإنشاء اليدوي يساعد على استيعاب الفكرة بشكل أعمق. يوضّح المثال التالي بنية مكوّن بسيط:

import { Component } from '@angular/core';

@Component({
  selector: 'app-hello-world',
  template: `<h2>{{ title }}</h2>`,
  styles: [`h2 { color: #dd0031; }`]
})
export class HelloWorldComponent {
  title = 'Hello World';
}

بعد إنشاء المكوّن، يجب تسجيله داخل AppModule أو أي Module مناسب، ثم استخدام selector الخاص به داخل قالب آخر.

Lifecycle Hooks: التحكم في دورة حياة المكوّن

توفّر Lifecycle Hooks آلية مهمة للتفاعل مع مراحل حياة المكوّن، مثل التهيئة والتحديث والتدمير. من أكثرها استخدامًا:

  • ngOnInit: يُستخدم عند تهيئة المكوّن لأول مرة.
  • ngOnChanges: يُستخدم عند تغيّر القيم المستقبلة.
  • ngOnDestroy: يُستخدم قبل إزالة المكوّن لتنظيف الموارد.

مثلاً، إذا أردت بدء عملية جلب بيانات عند تحميل الصفحة، فغالبًا ستستخدم ngOnInit. وإذا كان لديك اشتراك Subscription أو مؤقت زمني، فيُفضّل تنظيفه داخل ngOnDestroy لتفادي Memory Leaks.

import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-demo',
  template: `<p>Check console</p>`
})
export class DemoComponent implements OnInit, OnDestroy {
  intervalId: any;

  ngOnInit(): void {
    this.intervalId = setInterval(() => {
      console.log('Running...');
    }, 1000);
  }

  ngOnDestroy(): void {
    clearInterval(this.intervalId);
  }
}

Text Interpolation وربط النصوص الديناميكي

يُستخدم Text Interpolation لعرض البيانات القادمة من فئة TypeScript داخل HTML Template باستخدام الأقواس المزدوجة.

title = 'Hello World';
<h2>{{ title }}</h2>

هذه الطريقة مناسبة عندما تحتاج إلى جعل الواجهة ديناميكية، مثل عرض اسم مستخدم أو نتيجة عملية أو رسالة تفاعلية. ويمكن كذلك استدعاء دوال بسيطة داخل التعبيرات، لكن يُفضّل إبقاء المنطق المعقد داخل الفئة بدل القالب.

التواصل بين Components

في التطبيقات الحقيقية، نادرًا ما يعمل كل مكوّن بمعزل عن الآخر. لذلك من الضروري فهم آليات التواصل بين Components.

1) من الأب إلى الابن باستخدام Input

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<p>{{ childMessage }}</p>`
})
export class ChildComponent {
  @Input() childMessage!: string;
}
<app-child [childMessage]="'Hello from parent'"></app-child>

2) من الابن إلى الأب باستخدام Output

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-child',
  template: `<button (click)="sendMessage()">Send</button>`
})
export class ChildComponent {
  @Output() messageEvent = new EventEmitter<string>();

  sendMessage() {
    this.messageEvent.emit('Hello from child');
  }
}
<app-child (messageEvent)="receiveMessage($event)"></app-child>

3) الوصول المباشر عبر ViewChild

يُستخدم ViewChild عندما يحتاج المكوّن الأب إلى الوصول إلى خصائص أو دوال داخل المكوّن الابن مباشرة. هذه الطريقة مفيدة، لكن يُفضّل عدم الإفراط في استخدامها حتى لا يزداد الترابط بين المكوّنات.

تنسيق Components Styles داخل Angular

يوفّر Angular عدة طرق لتنسيق المكوّنات:

  • باستخدام styles داخل المكوّن.
  • باستخدام styleUrls لربط ملف خارجي.
  • بإدراج الأنماط مباشرة داخل القالب.

الميزة المهمة هنا أن Angular يطبّق افتراضيًا View Encapsulation، ما يجعل الأنماط خاصة بالمكوّن ولا تتسرّب لبقية التطبيق إلا إذا غيّرت هذا السلوك.

مثال على styles داخل المكوّن

@Component({
  selector: 'app-sample',
  template: `<h2>Styled Title</h2>`,
  styles: [`h2 { color: royalblue; }`]
})

كما يمكن استخدام محددات خاصة مثل :host و:host-context للتحكم في مظهر العنصر المضيف أو الاستجابة للسياق الخارجي.

ما هو Ng-Content ولماذا يفيدك؟

يُستخدم Ng-Content في Angular لتمرير محتوى HTML من مكوّن إلى آخر فيما يُعرف باسم Content Projection. هذه التقنية مفيدة جدًا عند بناء مكوّنات عامة قابلة لإعادة الاستخدام، مثل البطاقات والنوافذ والعناصر المركبة.

<h2>Card Title</h2>
<ng-content></ng-content>

وعند استخدام المكوّن:

<app-card>
  <p>This content will be projected</p>
</app-card>

يمكن أيضًا إنشاء أكثر من موضع عرض باستخدام select فيما يُعرف باسم Multi-slot Content Projection.

Template Statements والتفاعل مع الأحداث

عندما يتفاعل المستخدم مع زر أو عنصر إدخال أو أي حدث داخل الصفحة، نستخدم Template Statements لتنفيذ استجابة معينة.

<button (click)="toggleText()">Toggle</button>
showText = false;

toggleText() {
  this.showText = !this.showText;
}

هذه الآلية مهمة جدًا في بناء الواجهات التفاعلية، ويُفضّل أن تبقى العمليات المرتبطة بها واضحة وسريعة لتجنّب التأثير على تجربة المستخدم.

Pipes: تنسيق البيانات داخل القوالب

تُستخدم Pipes لتحويل البيانات أو تنسيقها داخل القوالب دون الحاجة إلى تعديل القيمة الأصلية. من الأمثلة الشائعة:

  • date
  • uppercase
  • currency
  • percent
{{ today | date:'fullDate' }}

كما يمكنك إنشاء Custom Pipe خاص بك:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'greetings'
})
export class GreetingsPipe implements PipeTransform {
  transform(value: string): string {
    return 'Hello ' + value;
  }
}
{{ 'World' | greetings }}

Property Binding وربط الخصائص

يعمل Property Binding على تمرير القيم من فئة TypeScript إلى خصائص عناصر HTML أو خصائص التوجيهات.

<img [src]="itemImageUrl" />

هذا النمط مهم عند التعامل مع خصائص مثل src وdisabled وvalue وغيرها. والفرق الأساسي هنا أن Angular يربط بالخصائص وليس بالسمات النصية فقط.

Attribute وClass وStyle Binding

Attribute Binding

يُستخدم عندما تحتاج إلى ربط قيمة بسمة لا تملك خاصية مباشرة مقابلة في DOM، مثل colspan.

<td [attr.colspan]="2">Content</td>

Class Binding

<div [class.active]="isActive">Item</div>

Style Binding

<div [style.color]="textColor">Text</div>

هذه الأدوات تتيح لك بناء واجهات أكثر مرونة، وتمنحك تحكمًا ديناميكيًا في المظهر والسلوك وفقًا لحالة البيانات.

Event Binding والتقاط أحداث المستخدم

يُستخدم Event Binding للتفاعل مع سلوك المستخدم مثل النقر والكتابة والتحريك واللمس.

<button (click)="onSave()">Save</button>
onSave() {
  console.log('Saved');
}

يمكن أيضًا استخدامه مع أحداث مخصصة صادرة من مكوّنات أخرى، وهو ما يجعله جزءًا محوريًا في بناء التفاعل داخل التطبيق.

Two-way Binding والمزامنة الثنائية

يجمع Two-way Binding بين Property Binding وEvent Binding في صيغة مختصرة، ويُستخدم كثيرًا في النماذج.

<input [(ngModel)]="username" />

هذا الربط يسمح بتحديث القيمة في الواجهة والفئة في الوقت نفسه، وهو مثالي للعناصر التي تتطلب إدخالًا مباشرًا من المستخدم.

Template Variables داخل القوالب

تُستخدم Template Variables للوصول إلى عنصر أو مكوّن أو نموذج من داخل القالب نفسه.

<input #phone />
<button (click)="callPhone(phone.value)">Call</button>

تُفيد هذه المتغيرات عندما تحتاج إلى التقاط قيمة سريعة أو مرجع لعنصر معيّن دون إنشاء خصائص إضافية داخل الفئة.

Directives: توجيه سلوك العناصر في Angular

تُعد Directives من أهم أدوات Angular. وهي فئات تضيف سلوكًا خاصًا للعناصر أو تغيّر بنية DOM. وتنقسم إلى ثلاثة أنواع رئيسية:

  • Components وهي نوع خاص من التوجيهات يملك قالبًا.
  • Attribute Directives لتغيير السلوك أو المظهر.
  • Structural Directives لتغيير بنية DOM.

أشهر Attribute Directives الجاهزة

  • NgClass
  • NgStyle
  • NgModel

مثال على Directive مخصص

import { Directive, ElementRef, HostListener, Input } from '@angular/core';

@Directive({
  selector: '[appHighlight]'
})
export class HighlightDirective {
  @Input() appHighlight = '';

  constructor(private el: ElementRef) {}

  @HostListener('mouseenter') onMouseEnter() {
    this.highlight(this.appHighlight || 'yellow');
  }

  @HostListener('mouseleave') onMouseLeave() {
    this.highlight('');
  }

  private highlight(color: string) {
    this.el.nativeElement.style.backgroundColor = color;
  }
}

Structural Directives: التحكم في بنية DOM

NgIf

تُستخدم لإظهار العناصر أو إخفائها وفق شرط معين.

<div *ngIf="isActive">Visible Content</div>

NgFor

تُستخدم للتكرار على القوائم.

<li *ngFor="let item of items; let i = index">{{ i }} - {{ item.name }}</li>

NgSwitch

تُستخدم لعرض أحد الخيارات بناءً على قيمة معيّنة.

<div [ngSwitch]="role">
  <p *ngSwitchCase="'admin'">Admin</p>
  <p *ngSwitchDefault>User</p>
</div>

Dependency Injection: هندسة أكثر نظافة ومرونة

يعتمد Angular بشكل كبير على Dependency Injection لتوفير الخدمات والمكونات القابلة لإعادة الاستخدام دون ربط مباشر ومتشابك بين الأجزاء.

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class LogService {
  logMessage(message: string) {
    console.log(message);
  }
}
constructor(private logService: LogService) {}

ngOnInit(): void {
  this.logService.logMessage('Component initialized');
}

هذا النمط يجعل التطبيق أسهل في الاختبار والتطوير، ويعزز إعادة استخدام المنطق داخل أكثر من مكوّن.

Routing: التنقل بين الصفحات داخل التطبيق

يسمح Angular Router ببناء تطبيقات متعددة الواجهات ضمن تجربة استخدام سلسة. ويمكنك من خلاله ربط المسارات بمكوّنات مختلفة، وتمرير Params، والتعامل مع الصفحات غير الموجودة، وإنشاء مسارات فرعية.

const routes: Routes = [
  { path: 'first', component: FirstComponent },
  { path: 'second', component: SecondComponent },
  { path: '', redirectTo: '/first', pathMatch: 'full' }
];
<a routerLink="/first">First</a>
<a routerLink="/second">Second</a>
<router-outlet></router-outlet>

تمرير المعاملات عبر المسارات

{ path: 'user/:id', component: UserComponent }

ثم يمكن قراءتها عبر ActivatedRoute داخل المكوّن.

Route Guards

تُستخدم Route Guards لحماية المسارات ومنع الوصول غير المصرّح به، مثل التحقق من تسجيل الدخول أو الصلاحيات.

Template-Driven Forms: النماذج المبنية على القالب

تُعد Template-Driven Forms خيارًا مناسبًا للنماذج الصغيرة والبسيطة. تعتمد هذه المقاربة على التوجيهات داخل القالب، وتستخدم FormsModule.

<form #userForm="ngForm" (ngSubmit)="onSubmit()">
  <input name="name" [(ngModel)]="model.name" required />
  <button type="submit" [disabled]="!userForm.form.valid">Submit</button>
</form>

هذه الطريقة سهلة الفهم للمبتدئين، وتمنحك إمكانية ربط الحقول مباشرة بنموذج البيانات مع التحقق الأساسي من الصحة.

Reactive Forms: تحكم أكبر بالنماذج

عندما تصبح النماذج أكثر تعقيدًا، تكون Reactive Forms هي الخيار الأفضل. فهي تعتمد على نموذج بيانات يُبنى داخل فئة TypeScript باستخدام ReactiveFormsModule.

import { FormGroup, FormControl } from '@angular/forms';

profileForm = new FormGroup({
  firstName: new FormControl(''),
  lastName: new FormControl('')
});
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
  <input formControlName="firstName" />
  <input formControlName="lastName" />
  <button type="submit">Save</button>
</form>

هذا الأسلوب يوفّر مرونة أكبر في التحقق، والتتبع، والتحديث البرمجي، وإدارة الحالات المعقدة.

Form Validation: التحقق من صحة المدخلات

التحقق من صحة البيانات ليس مجرد تحسين شكلي، بل هو جزء أساسي من جودة التطبيق وأمانه وتجربة استخدامه. يدعم Angular التحقق في كل من Template-Driven Forms وReactive Forms.

التحقق في Template-Driven Forms

<input name="name" [(ngModel)]="name" required minlength="4" #nameModel="ngModel" />

<div *ngIf="nameModel.invalid && (nameModel.dirty || nameModel.touched)">
  <div *ngIf="nameModel.errors?.['required']">الاسم مطلوب</div>
  <div *ngIf="nameModel.errors?.['minlength']">يجب ألا يقل الاسم عن 4 أحرف</div>
</div>

التحقق في Reactive Forms

import { Validators, FormControl } from '@angular/forms';

name = new FormControl('', [Validators.required, Validators.minLength(4)]);

ميزة Reactive Forms هنا أنها تمنحك تحكمًا أوضح في القواعد والحالة، خاصة في المشاريع الكبيرة.

HTTP Client: التواصل مع الخوادم وAPIs

لا تكتمل أغلب تطبيقات الويب الحديثة دون التواصل مع الخوادم. ومن خلال HTTP Client يوفّر Angular أدوات مرنة لجلب البيانات وإرسالها وإدارة الأخطاء.

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  constructor(private http: HttpClient) {}

  getData() {
    return this.http.get('https://example.com/api/data');
  }
}
constructor(private dataService: DataService) {}

ngOnInit(): void {
  this.dataService.getData().subscribe(data => {
    console.log(data);
  });
}

معالجة الأخطاء

من الجيد ألا تفترض نجاح الطلب دائمًا. عند فشل الاتصال أو حدوث خطأ من الخادم، يجب عرض رسالة مناسبة للمستخدم وتسجيل الخطأ للمطور.

import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

getData() {
  return this.http.get('https://example.com/api/data').pipe(
    catchError(error => {
      console.error(error);
      return throwError(() => new Error('Request failed'));
    })
  );
}

إرسال Headers ومفاتيح API

import { HttpHeaders } from '@angular/common/http';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  })
};

هذا النمط شائع جدًا عند التعامل مع الخدمات التي تتطلب مصادقة أو إعدادات خاصة في الطلبات.

كيف تبدأ عمليًا مع Angular؟

  1. ثبّت Angular CLI.
  2. أنشئ مشروعًا جديدًا باستخدام الأمر المناسب.
  3. ابدأ بفهم Components وBinding.
  4. انتقل إلى Directives وRouting.
  5. تدرّب على Forms وHTTP Client.
  6. طبّق كل مفهوم ضمن مشروع صغير بدل الاكتفاء بالمشاهدة النظرية.
ng new project-name

أفضل طريقة لتعلّم Angular ليست حفظ المصطلحات، بل استخدام كل مفهوم داخل تطبيق فعلي، ولو كان بسيطًا في البداية.

نصائح مهمة للاستفادة القصوى من دورة Angular

  • لا تنتقل إلى المفاهيم المتقدمة قبل إتقان أساسيات Components وBinding.
  • اكتب الأكواد بنفسك بدل الاكتفاء بالقراءة.
  • قسّم التطبيق إلى مكوّنات صغيرة منطقية.
  • استخدم Services عند تكرار المنطق البرمجي.
  • تعلّم قراءة الأخطاء في المتصفح والكونسول، فهي جزء أساسي من التطوير.
  • درّب نفسك على بناء نموذج، ثم إضافة التحقق، ثم ربطه بـ API.

الخلاصة التقنية

Angular إطار عمل قوي ومناسب جدًا لبناء تطبيقات ويب منظمة وقابلة للتوسع، خصوصًا عندما يكون المشروع كبيرًا أو يتطلب بنية واضحة طويلة الأمد. هذه الدورة المكثفة تمنحك مسارًا عمليًا يمر على أبرز المفاهيم التي يحتاجها أي مطور مبتدئ أو متوسط، بدءًا من Components وBinding وحتى Routing وForms وHTTP Client. تقنيًا، أفضل ما يميز Angular هو اتساقه المعماري واندماجه القوي مع TypeScript، ما يجعله خيارًا ممتازًا لمن يريد بناء تطبيقات احترافية قابلة للصيانة على المدى الطويل.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *