בחלק הזה נבנה אפליקציית אנגולר שמכילה בתוכה שימוש במספר קומפוננטות מיועדות לשימוש חוזר באפליקציה. נשתמש ב-Bootstrap לעצב את הקומפוננטות. לאפליקציה יהיה סרגל ניווט שיעבור בין כל עמודי האפליקציה.
יהיו כמה אתגרים בבניית האפליקציה: יישום הניווט בין העמודים. יצירת הקומפוננטות השונות, בעלות קשר ביניהן, תחת אותו מודל. כל הקומפוננטות צריכות להיות בעלות יכולת לשימוש חוזר.
את הפרוייקט הבא ניצור עם קבצי routing של אנגולר.
ng new comps
//לבחור Y בשאלה האם להוסיף routing
מהו מודול?
מודול (Module) הוא יחידה באנגולר שמאגדת בתוכה קומפוננטות עם עניין משותף.
יצירת מודול
נשתמש בשורת הפקודה ליצירת מודול. ניצור מראש את 4 המודולים שנשתמש בהם.
ng g m elements --routing
ng g m collections --routing
ng g m views --routing
ng g m mods --routing
נוצרה לנו תיקייה עבור כל מודול. בתוך התיקייה קובץ המודול וקובץ הניווט.
נתקין גם את bootstrap על מנת להשתמש בעיצוב שלהם.
יצירת קומפוננטה
את הקומפוננטה נייצר בתוך התיקייה של המודול כדי לשמור על סדר.
ng g c elements/elementsHome
אם ננסה להשתמש בקומפוננטה הזאת בקובץ app היא לא תהיה זמינה. כל קומפוננטה מוכרת בתוך המודל שבו היא נוצרה. כדי להיא תהיה מוכרת במקום אחר, צריך לעשות לה export.
כדי לעשות את זה נוסיף את exports לקובץ ה-module.
קובץ elements.module.ts
@NgModule({
declarations: [
ElementsHomeComponent
],
imports: [
CommonModule,
ElementsRoutingModule
],
exports: [
ElementsHomeComponent
]
})
export class ElementsModule { }
נוסיף import של המודול ElementsModule ל-app.
קובץ app.module.ts
import { ElementsModule } from './elements/elements.module';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ElementsModule
],
providers: [],
bootstrap: [AppComponent]
})
נבצע את פעולת יצירת הקומפוננטה והייצוא שלה עבור שאר המודולים. נציג את הקומפוננטות בעמוד app.component.html.
קובץ app.component.html
<app-elements-home></app-elements-home>
<app-collections-home></app-collections-home>
<router-outlet></router-outlet>
ניווט בין קומפוננטות
כרגע אפשר לראות את הצגת כל הקומפוננטות באותו העמוד, אנחנו רוצים שלפי הקישור המסך יציג לנו את הקומפוננטה המתאימה ולא את כולן יחד.
כדי לאפשר לתוכן של קומפננטת ה-elements להופיע בקישור של מודול elements, אנחנו צריכים להוסיף קישור לעמוד ולהגיד מה להציג כשנכנסים לקישור הזה.
ננקה את העמוד הראשי ונשאיר בו רק את מנגנון הניווט.
קובץ app.component.html
<router-outlet></router-outlet>
אנחנו כבר לא צריכים לבצע export לקומפוננטה של ElementsHomeComponent כי היא תופיע דרך המודול שלה. נסיר את הייצוא של הקומפוננטות.
בקובץ elements-routing.module.ts נייבא את הקומפוננטה שרוצים להציג וניצור כלל ניווט.
קובץ elements-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ElementsHomeComponent } from './elements-home/elements-home.component';
const routes: Routes = [
{ path: 'elements', component: ElementsHomeComponent }
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ElementsRoutingModule { }
את אותה הפעולה נבצע על שאר המודולים.
בקובץ app.component.html יש לנו את רכיב <router-outlet></router-outlet>.
האלמנט הזה מגדיר את המקום שבו יפיע התוכן של הקומפוננטה אליה אנחנו מנווטים.
הוספת סרגל ניווט
כשאנחנו מוסיפים את סרגל הניווט בקובץ app.component.html הוא יופיע בכל הדפים ומתחתיו התוכן של העמוד. פה הוספתי סרגל מתוך תיעוד bootstrap. כרגע הניווט הוא על ידי קישור פשוט.
קובץ app.component.html
<div class="container mt-5 mb-5">
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link active" href="/elements">Elements</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/collections">Collections</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Views</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Modules</a>
</li>
</ul>
<div class="border bg-light mt-4 p-3">
<router-outlet></router-outlet>
</div>
</div>
הניווט עובד, אבל הבעיה היא שהוא מפספס את כל הרעיון של אפליקציה בעמוד אחד. לחיצה על קישור טוענת מחדש את כל העמוד במקום רק את החלק שמשתנה בעמוד. במקום href נשתמש ב-routerLink. עכשיו לא תהיה טעינה של כל העמוד בלחיצה על הקישורים.
<div class="container mt-5 mb-5">
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link active" routerLink="/elements">Elements</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLink="/collections">Collections</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Views</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Modules</a>
</li>
</ul>
<div class="border bg-light mt-4 p-3">
<router-outlet></router-outlet>
</div>
</div>
עיצוב קישור Active בתפריט
אנגולר מזהה את הקישור הפעיל על ידי routerLinkActive ונותן לנו אפשרות להוסיף class שיופעל במידה והקישור פעיל.
<ul class="nav nav-pills">
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" routerLink="/elements">Elements</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" routerLink="/collections">Collections</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" routerLink="/viewa">Views</a>
</li>
<li class="nav-item">
<a class="nav-link" routerLinkActive="active" routerLink="/mods">Modules</a>
</li>
</ul>
קביעת עמוד הבית
כדי שהגולש יגיע לעמוד מסויים בהכנסת כתובת הבסיס, אנחנו צריכים להגיד לאנגולר מה העמוד הזה.
ניצור קומפוננטה ונקרא לה Home. היא תשב תחת app כי היא לא שייכת לאף מודול אחר. את הניווט לקומפוננטה הזאת נעשה דרך קובץ הניווט הראשי של app מכיוון שזהו ניווט כללי שלא פונה למודול מסויים, אלא ישירות לקומפוננטה.
נייבא את HomeComponent ונוסיף את ה-route המתאים.
קובץ app-routing.module.html
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
const routes: Routes = [
{ path: '', component: HomeComponent }
];
עמוד שגיאה
מה קורה כשגולש מכניס כתובת שאין לה עמוד מתאים? ניצור קומפוננטה שתופיע כאשר יש לנו גלישה לעמוד שלא קיים, נקרא לה NotFound. גם אותה נייבא לקובץ ה-routing של app ונוסיף את המסלול שלה. שני * מסמנים נתיב שלא קיים, כלומר לא נמצא בשום קובץ routing.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './components/home/home.component';
import { NotFoundComponent } from './components/not-found/not-found.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: '**', component: NotFoundComponent }
];
תהיה לנו בעיה כי אחרי בדיקה של עמוד הבית, יש לנו בדיקה של **, מה שאומר שכל נתיב שנכניס, גם אם הוא קיים, לא יעבוד. סדר הקריאות ל-routes הוא חשוב, כי ברגע שנמצא route מתאים, אנגולר לא ממשיך לחפש התאמה אחרת.
הסדר שבו נקראים הנתיבים נמצא בקובץ app.module.ts. בחלק ה-imports, שם יש לנו:
imports: [
BrowserModule,
AppRoutingModule,
ElementsModule,
CollectionsModule
],
ה-AppRoutingModule מופיע לפני המודולים האחרים ולכן הוא נקרא קודם. כל מה שצריך לעשות זה להעביר את AppRoutingModule לסוף.