如何在 Angular 建立 Route ?
傳統以後端為主的 MVC 寫法,route 會寫在後端;前後端分離的 SPA 寫法,前後端有各自的 route,前端的 route 負責切換 component,而後端的 route 則負責 API。
Version
macOS High Sierra 10.13.3
Node.js 8.9.4
Angular CLI 1.6.7
Angular 5.2.4
建立 Route
建立專案時一併建立 Route
| 1 | $ ng new MyProject --routing | 
新建專案時,加上 --routing 參數。

- Angular CLI 會替我們在 src/app目錄下新增app-routing.module.ts檔案
- class 名稱為 AppRoutingModule
- routes陣列即位自訂 route 之處
第 7 行
| 1 | imports: [RouterModule.forRoot(routes)], | 
一般來說,imports 要的都是單純 module,如 BrowserModule,但這裡用的卻是 RouterModule.forRoot()。
- forRoot()為- RouterModule的 factory method,為- static, 傳入- routes後,回傳給- AppModule所使用的- RouterModule
- forChild()亦為- RouterModule的 factory method,為- static,傳入- routes後,回傳其他 module 所使用的- RouterModule
之所以要特別用
forRoot()與forChild(),因為當AppModule與其他 module 都 importRouterModule時,由於其他 module 都有自己的 DI injector,會屏蔽AppModule的Router,有就是說Router將不再整個 app 共用,而是各 module 有自己的Router,因此RouterModule特別不提供 provider,而是改由forRoot()與forChild()提供,如此整個 app 將只會有一份Router

- Angular CLI 還替我們修改了 app.module.ts
- 自動將 AppRoutingModuleimport 進來
理論上
app.module.ts與app-routing.module.ts可以合一,但因為app.module.ts有他原本的職責,如declarations、imports、providers與bootstrap,且簡單的 app 也可能也沒使用 route,因此特別將 route 部分特別獨立為app-routing.module.ts,再 import 進app.module.ts即可
建立專案後事後加上 Route
假如一開始建立專案時沒加上 --routing ,也可事後再建立 route。
Angular CLI 並沒有提供單獨建立 route 的指令,只能在建立 module 時,順便加上
--routing參數建立 route
將 app.module.ts 暫時改名

- 將 app.module.ts暫時改名為app.module.ts.bak
因為我們即將重建
app.module.ts,所以先將目前的app.module.ts改名避開
重新建立有 Route 的 AppModule
| 1 | ~/MyProject $ ng g m App --flat --routing | 
m : module 的縮寫
--flat : 不要將 AppRouting 建立在目前目錄下,而是建立在 src/app 目錄下
--routing : 一併建立 AppRoutingModule

- 在專案目錄下執行 ng g m App --flat —routing
- Angular CLI 會替我們建立 app.module.ts與app-routing.module.ts兩個檔案
- 在 AppModule中,會自動幫我們 importAppRoutingModule
刪除 app.module.ts
Angular CLI 剛剛幫我們建立了全新的 app.module.ts,手動將此檔刪除
因為我們目的是要 Angular CLI 幫我們建立
app-routing.module.ts,app.module.ts沒有利用價值需刪除
將 app.module.ts.bak 改為 app.module.ts

- 將 app.module.ts刪除,再將app.module.ts.bak重新命名為app.module.ts
app.module.ts.bak才是我們原本的app.module.ts
修改 AppModule

- 選擇 app.module.ts
- 在 imports加上剛剛建立的AppRoutingModule
修改 AppRoutingModule

- 選擇 app-routing.module.ts
- 將 forChild()改成forRoot()如此無論是一開始建立專案就加上 --routing參數,或者先建立專案,事後再補建立 route,目前AppModule都有相同的AppRoutingModule
設定 Route
建立 Login 與 Post Component
使用一般建立 component 的方式建立 LoginComponent 與 PostComponent (略)
設定 routes
app-routing.module.ts
| 1 | import { NgModule, Component } from '@angular/core'; | 
第 6 行
| 1 | const routes: Routes = [ | 
Routes 為 Angular 定義的 Route 陣列,用來設定 user 自己的 route 定義。
第 7 行
| 1 | { path: 'login', component: LoginComponent }, | 
- path: 設定 route 路徑
- component: 當符合- path定義時,該顯示的 component
當 URI 為 login 時,顯示 LoginComponent
第 8 行
| 1 | { path: 'post', component: PostComponent }, | 
當 URI 為 post 時,顯示 PostComponent
第 9 行
| 1 | { path: '', redirectTo: '', pathMatch: 'full' }, | 
- redirectTo: redirect 到其他 URI 路徑
- pathMatch: 與- path的匹配方式
當  URI 為 空字串,redirect 到 '',且必須完全符合 path 定義
使用 router-outlet 與 routerLink
app.component.html
| 1 | Welcome to {{ title }}! | 
第 6 行
| 1 | <router-outlet></router-outlet> | 
當在 AppRoutingModule 的 routes 設定 component 時,會顯示在哪呢 ? 就是顯示在 HTML template 的 <router-outlet></router-outlet> 內。
第 2 行
| 1 | <a routerLink="login">Login</a> | 
原本的 <a> 會使用 href,但這會導致 Angular 使用後端的 route,也就是整個網頁會重新載入;若使用 routerLink,則 Angular 會使用前端的 route,也就是將 <router-outlet></router-outlet> 換成其他 component,使用者體驗較好。
Conclusion
- Angular 也有自己的 route,傳統頁面跳轉的 route 必須改設定在 Angular
Sample Code
完整的範例可以在 GitHub 上找到