כתיבת אפליקציית אנגולר מתבצעת ע"י כתיבת HTML שבתוכו משולבים תוספות של
אנגולר, כתיבת components כדי לשלוט על ה-templates, כתיבה של services כדי לשלוט על הלוגיקה,
ושילוב של components ו- services ליצירת modules.
הארכיטקטורה של אנגולר (מתוך האתר הרשמי, גם
הדוגמאות שלהלן יהיו מאותו האתר):
באיור לעיל ניתן לראות את שמונה אבני הבניין הראשיים של אנגולר 2:
- Modules
- Components
- Templates
- Metadata
- Data binding
- Directives
- Services
- Dependency injection
1. Modules
באנגולר מסמנים module ע"י @NgModule. בכל אפליקציית אנגולר יש לפחות module אחד. באפליקציות קטנות יכול להיות רק module אחד (שהוא ה-root
module), אבל ברוב האפליקציות יהיו מספר modules. כל module מיועד לפיצ'ר מסוים (feature module), או לסט של פיצ'רים באותו תחום. כל module הוא class עם decorator של @NgModule.
במאמר מוסגר נציין ש- decorator זה בעצם פונקציה שמתאימה
את ה-class של JS לטובת אנגולר. באנגולר יש
המון סוגים של decorator שמוסיפים metadata ל-class כך שאנגולר יידע מה לעשות
עם כל class.
ה- NgModule decorator, זו פונקציה שלוקחת
אובייקט metadata שמתאר את ה-module. השדות העיקריים באובייקט ה-metadata הם:
·
declarations – מכיל את
ה-view classes שמשתייכים ל-module הזה. באנגולר יש שלוש סוגים של view classes, שהם: components, directives ו-pipes.
·
exports – מכיל
רשימה מתוך ה-declarations שצריכה להיות זמינה
לשימוש ב-templates של components של modules אחרים.
·
imports – מכיל
רשימה מתוך ה-declarations שיוצאו (נכללו ברשימת exports) מ-modules אחרים ושנצרכים לטובת ה-templates ב-components שב-module הנוכחי.
·
providers – מכיל
רשימה של services שנמצאים ב-module הנוכחי. ה-services יהיו זמינים בכל
האפליקציה (ולא רק ב-module הנוכחי).
·
bootstrap – מכיל את
ה-view הראשי של האפליקציה (נקרא גם root component). השדה bootstrap צריך להיות רק ב-module הראשי (root module).
דוגמא ל-root module בסיסי:
app/app.module.ts:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ],
providers: [ Logger ],
declarations: [ AppComponent ],
exports: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
בד"כ הצורה שבה משתמשים ב-root module כ-Module הראשוני היא:
app/main.ts:
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
ספריות אנגולר
אנגולר זה אוסף של JS modules (יש הבדל בין JS modules ל-angular modules. כל קובץ JS הוא בעצם JS module). כל ספריה של אנגולר
מתחילה עם @angular. כדי להשתמש בספריה של
אנגולר צריך לייבא אותה ע"י import לדוגמא:
import { Component } from '@angular/core';
גם angular modules מיבאים בצורה דומה.
לדוגמא:
import { BrowserModule } from '@angular/platform-browser';
2.
Components
ה-component שולט על חלק מהתצוגה, גם
מבחינת המראה וגם מבחינת הלוגיקה. מגדירים את הלוגיקה של ה- component בתוך class, וה-class מתקשר עם התצוגה ע"י
API של properties ו-methods.
3.
Templates
את התצוגה של ה- component מגדירים בשדה של ה-template שלו. ה-template זה בעצם קטע של HTML שמגדיר לאנגולר איך לרנדר
את התצוגה. ב-template משלבים בטקסט ה-HTML גם שימוש בקוד של אנגולר. לדוגמא:
<h2>Hero List</h2>
<p><i>Pick a hero
from the list</i></p>
<ul>
<li *ngFor="let
hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
בדוגמא זו ניתן לראות שימוש ב-*ngFor, ובכל מיני סוגריים שהם חלק מה-syntax של אנגולר כמו {{hero.name}}, (click), [hero]. כמו כן ניתן לראות שימוש בתג חדש שיצרנו <hero-detailed> שמייצג את ה-component שיצרנו HeroDetailComponent.
4.
Metadata
ה-metadata מכיל מידע שמסביר לאנגולר
מה לעשות עם ה-class. ב-TypeScript מצמידים metadata ל-class ע"י decorator. לדוגמא:
@Component({
moduleId: module.id,
selector: 'hero-list',
templateUrl: 'hero-list.component.html',
providers: [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}
בדוגמא זו ניתן לראות component decorator שמזהה את ה-class שכתוב לאחריו כ-component
class. ה-decorator מקבל configuration object שמכיל את המידע הנצרך לאנגולר כדי ליצור את
ה-component ואת ה-view שלו:
·
moduleId – קובע את
ה-base address ל-URLs היחסיים, כמו templateUrl.
·
selector – זהו CSS selector שמייצג את ה-component הנוכחי. בכל מקום ב-HTML שיופיע ה-selector הזה - <hero-list>, אנגולר יכניס לשם את ה-view של ה-component הזה.
·
templateUrl – מיקום
יחסי של HTML template של ה-component.
·
providers – מערך של services שנדרשים ל-component הנוכחי מה-dependency injection.
אפשר לסכם שה-metadata מספק לאנגולר רשימה של
אבני הבניין שנדרשים ל-component.
ה-template יחד עם ה-metadata וה-component מתארים את ה-view.
5.
Data binding
אנגולר מספק מספר אפשרויות של data binding בין ה-component ל-DOM:
1. מה-component ל-DOM
2. מה-DOM ל-component
3. לשני הכיוונים (two way data binding)
לדוגמא:
<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<li (click)="selectHero(hero)"></li>
·
שימוש
בסוגריים מסולסלים כפולים, {{hero.name}}, נקרא interpolation. צורה זו היא דוגמא של data binding מספר 1. הערך של ה-hero.name
property יוצג באלמנט <li>.
·
שימוש
בסוגריים מרובעים, [hero], נקרא property binding. גם צורה זו היא דוגמא של data binding מספר 1. במקרה הזה הערך של selectedHero יועבר ל-hero property, ולאחר מכן יוצג ב-DOM ע"י HeroDetailedComponent.
·
שימוש
בסוגריים עגולות, (click), נקרא event binding. צורה זו היא דוגמא של data binding מספר 2. כאן מועבר מידע (במקרה הזה event) מה-DOM אל ה-component.
ה-data binding מספר 3, שנקרא two way data binding, משלב property
binding יחד עם event binding. צורת הישמוש היא ע"י סוגריים עגולים בתוך סוגריים מרובעים,
לדוגמא:
<input [(ngModel)]="hero.name">
ב- two way
data binding אם ה-property משתנה ב-component אז הוא ישתנה גם ב-DOM (לדוגמא ב-input box), כמו ב-property
binding. ואם המשתמש שינה את הערך ב-DOM אז השינוי יעבור גם ל-component, כמו ב-event binding.
באנגולר עושים הרבה שימוש ב-binding בתקשורת בין ה-template ל-component. כמו כן, משתמשים בזה גם
בתקשורת בין component אבא ל-component בן.
6.
Directives
ה-directive הוא class עם decorator של @directive. ה-component הוא בעצם directive עם template, אך כיון שהוא כל כך חשוב
באריכטקטורה של אנגולר, ישנה הפרדה בהסבר בים component ל-directive.
ישנם שני סוגים נוספים של directive:
·
Structural
directive
·
Attribute
directive
ה-structural directive משנה את התצוגה ע"י
הוספה, הסרה או החלפה של אלמנטים ב-DOM. לדוגמא:
<li *ngFor="let
hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
ה-*ngFor אומר לאנגולר לתת <li> אחד לכל hero מרשימת heros.
ה-*ngIf מציג את ה-heroDetail component רק אם ה-hero הנבחר קיים.
ה-attribute directive משנה את התצוגה או את
ההתנהגות של אלמנט קיים. ב-template ה-directive הזה נראה כמו HTML attributes רגילים, ולכן זה נקרא attribute
directive.
ה-ngModel directive, שנותן לנו two way data binding, הוא דוגמא ל-attribute
directive. ה-ngModel משנה את ההתנהגות של
אלמנטים קיימים ע"י השמה של ערכים לתצוגה של האלמנט (ל-<input> למשל), וע"י תגובה
ל-event של שינוי.
<input [(ngModel)]="hero.name">
באנגולר יש עוד כמה directives, לדוגמא: ngSwitch, ngStyle, ngClass. כמו כן יש אפשרות לכתוב directive בעצמנו.
7.
Services
ה-service זה class שמספק לנו שירות מסוים.
למשל: logging service, data service, tax calculator,
application configuration.
ה-services זה אחד מאבני היסוד של
אנגולר. ה-components הם הצרכנים הראשים של services. דוגמא ל-service פשוט:
export class Logger {
log(msg: any) { console.log(msg); }
error(msg: any) {
console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
ה-components אמורים להיות יחסית
קטנים. ב-component לא מיישמים את התקשורת עם
השרת, לא עושים input validation וגם לא מיישמים כתיבה ל-console. כל זה ודברים דומים לכך מיישמים ב-services.
התפקיד של ה-component זה לדאוג לחויית ההמשתמש.
הוא מאגד את ה-view (ממומש ב-template) יחד עם הלוגיקה. אבל אנגולר לא כופה את
הארכיטקטורה הזו, וגם אם ה-component יטפל בהכל בעצמו מבחינת
אנגולר זה יהיה בסדר. אנגולר עוזר במימוש הארכיטקטורה הזו ע"י כך שהוא עושה
את ה-services זמינים לכל ה-components בעזרת ה-dependency injection.
8.
Dependency
injection
ה- dependency
injection זו הדרך לספק לכל class חדש את כל הדברים שהוא
תלוי בהם. רוב ה-dependencies הם services. אנגולר יודע מה ה-services הדרושים ל-component מתוך הפרמטרים שב-constructor. לדוגמא:
constructor(private service: HeroService) { }
ה-class הזה צריך את HeroService.
כאשר אנגולר יוצר component הוא בהתחלה מבקש מה-injector את ה-services הדרושים. ה-injector מבחינתו מתחזק container של services
instances שהוא יצר עד כה. אם ה-service המבוקש קיים כבר ב-container אז אנגולר קורא ל-constructor של ה-component עם כל ה-services הדרושים. אם לאחד ה-services עדיין אין instance ב-container אז ה-injector יוצר instance של ה-service ושומר אותו ב-container לפני שהוא חוזר לאנגולר.
רק לאחר שכל ה-services הדרושים שמורים ב-container רק אז אנגולר קורא ל-constructor של ה-component עם כל ה-services הדרושים.
כאשר ה-injector צריך ליצור instance של service מסוים, הוא משתמש במערך providers שהוא זה שיכול ליצור instance של service. ניתן לכתוב את ה-providers ב-modules או ב-components. באופן כללי, עדיף לכתוב את כל ה-providers ב-root module. כך שאותו instance של service יהיה קיים בכל האפליקציה.
ניתן גם לכתוב providers בתוך component. המשמעות היא שנוצר instance חדש של service לכל instance חדש של ה-component.
כמה נקודות חשובות לגבי ה-dependency injection:
·
ה-DI הוא חלק מאנגולר ונמצא בשימוש בכל האפליקציה
·
ה-DI מייצר ומתחזק container של services
instances
·
ה-DI יכול ליצור instance חדש של service ע"י שימוש ב-provider.
9.
סיכום
·
למדנו את
שמונה אבני הבנין של אנגולר, הכוללים את:
·
Modules
·
Components
·
Templates
·
Metadata
·
Data binding
·
Directives
·
Services
·
Dependency
injection
וזה ידע בסיסי טוב כדי להתחיל ולכתוב אפליקציות אנגולר 2.
כמובן שיש עוד הרבה מה ללמוד. להלן מספר נושאים חשובים באנגולר:
Animations – ניתן
ליצור component לאנימציה גם בלי ידע נרחב
באנימציות, ע"י שימוש בספרית האנימציה של אנגולר.
Change detection – הצורה
שבה אנגולר מחליט שהערך של-property של component מסוים השתנה, ומתי לעדכן
את המסך.
Events – גם components וגם services יכולים לשלוח events. כמו כן, כל מנגנוני פרסום ה-event והרשמה ל-event גם כלולים כאן.
Forms - תומך בתרחישי הכנסת נתונים מורכבים עם
וולידצית HTML-based.
HTTP – נועד
לצורך יצירת קשר עם השרת כדי לקבל מידע, לשמור מידע, ולקלוט את ה-server side actions ע"י ה-HTTP
client.
Lifecycle hooks – מאפשר
להתחבר לנקודות מרכזיות במחזור החיים של components, מיצירת ה-component ועד לסגירתו ע"י שימוש ב-lifecycle hook interface.
Pipes – משמשים
לשיפור ה-UX בכך שהם משנים תצוגה של
ערכים מסוימים. לדוגמא, הצגת ערך כספי:
price | currency:'USD':true
יציג 42.33$.
Router – ניווט
מדף לדף בתוך ה-client בלי לעזוב את ה-browser.
Testing – שימוש ב-Angular Testing Platform לצורך הרצת unit tests על האפליקציה.בקיצור, יש עוד הרבה מה ללמוד, אז קדימה חבל על הזמן...
אפשר להראות דוגמאות
השבמחקזה מאמר על הארכיטקטורה של אנגולר ולכן הוא כללי מדיי בשביל דוגמאות. במאמר על הראוטינג, שזה נושא יותר ספציפי יש דוגמאות.
מחקתודה על המידע זה סידר לי משהו בראש כתוב בצורה מאוד ברורה ומסביר תאורתית חלקים שצריכים הבנה כזאת
השבמחקתודה רבה רבה!
תגובה זו הוסרה על ידי המחבר.
מחקשמח לשמוע שזה מובן. בהצלחה
מחקתודה רבה!!
השבמחקאתה מסביר מעולה!
תודה רבה לך אנונימי יקר
מחק