เนื้อหาต่อไปนี้ เราจะมาดูวิธีการใช้งาน routing module หลายๆ อันพร้อมกัน เช่น สมมติว่า
app ของเรามีขนาดใหญ่ขึ้น มีการแยก module หลาย module และมีไฟล์ routing module
ของ module ย่อยเพิ่มเข้ามา เนื้อหานี้จะต่อเนื่องจากตอนที่แล้ว
จัดการ Routing ผ่าน Routing Module ใน Angular ตอนที่ 2 http://niik.in/842
https://www.ninenik.com/content.php?arti_id=842 via @ninenik
จากเนื้อหาการใช้งาน routing ในตอนที่ผ่านๆ มา เรามีการสร้าง component ต่างๆ เพิ่มมา 4 ส่วน ได้แก่
home, user, pagenofound และ product ทีนี้ เราต้องการจะจัดการเกี่ยวกับ product แยกออกมาเฉพาะ
โดยให้มี module เฉพาะของ product มี routing เฉพราะของ product ซึ่งเป็น routing ย่อยของ AppRoutingModule
หลักอีกที และมี component เฉพาะที่ใช้งานใน module product นี้ด้วย
ให้นึกภาพ module product ที่เราจะสร้างขึ้นมา คือ เมื่อคลิกเข้ามาหน้า product จากหน้าหลัก ก็จะแสดงรายการ product ทั้งหมด
หรือก็คือหน้า product list มีรายการ product แสดงอยู่ ถ้าผู้ใช้คลิกที่รายการใดๆ เพื่อดูรายละเอียด ก็จะลิ้งค์ไปหน้ารายละเอียดของ
product หรือก็คือหน้า product detail แบบนี้เป็นต้น
การสร้าง Module ใหม่
ดังนั้นเราจะสร้างส่วนของ product ใหม่ ก่อน ให้เราลบโฟลเดอร์ product เดิมที่มี product component ออก
แล้วสร้าง product module และ product-routing module เพิ่มเข้ามา โดยใช้คำสั่ง ผ่าน command line ดังนี้
C:\projects\simplerouter>ng g module product --routing
เราจะได้ไฟล์ product.module.ts และไฟล์ product-routing.module.ts ในโฟลเดอร์ product
สังเกตว่า การต่อท้ายด้วย --routing จะทำให้เราได้ไฟล์ routing module เพิ่มเข้ามา หากไม่กำหนด เราก็จะได้เฉพาะไฟล์
product.module.ts แต่อย่างไรก็ตาม เราสามารถสร้างไฟล์ product-routing.module.ts เพิ่มขึ้นมาเองทีหลังแทนการ generate ก็ได้
การสร้าง Component ใน Module ใหม่
จากนั้นสร้าง component เพิ่่มเข้ามาอีก 2 อัน คือ product-list กับ product-detail ไว้ใน module product ด้วยคำสั่ง
C:\projects\simplerouter>ng g c product/product-list --flat
C:\projects\simplerouter>ng g c product/product-detail --flat
เราจะได้ไฟล์ product-list และ product-detail ที่ประกอบไปด้วยไฟล์ html css spec และ ts ไฟล์ โดยจะอยู่ในโฟลเดอร์ product
ซึ่งเป็น module ที่เรากำหนดในขั้นตอนการ generate ตามรูปด้านล่าง
นอกจากนั้นเราจะพบว่า ในการ generate ไม่มีการสร้างโฟลเดอร์ย่อยที่ชื่อ product-list และ product-detail
เพิ่มเข้ามาในโฟลเดอร์ product อีก ทั้งนี้ก็เพราะ เรากำหนด --flat ต่อท้าย ซึ่งหมายถึง ไม่ต้องสร้างโฟลเดอร์เพิ่ม
ความสัมพันธ์ของทั้ง 2 component ที่สร้างขึ้นมานี้ ก็คือ product-list จะแสดงรายการ product ทั้งหมด และ
product-detail ก็จะแสดงรายละเอียดของ product ที่ได้เลือกจากหน้า product-list อีกที
เราจะสมมติการใช้งานอย่างง่าย โดยยังไม่ลงรายละเอียดในขั้นตอนการส่งค่าผ่าน routing จะใช้วิธีกำหนดค่าแบบตายตัวไปก่อน
ให้กำหนดโค้ดในไฟล์ทั้งสอง เป้นดังนี้
ไฟล์ product-list.component.html
<p> product-list works! </p> <table class="table"> <tr> <td>Product Detail 1 </td> <td> <a class="btn btn-sm btn-success" routerLink="/product/1" routerLinkActive="active"> View </a> </td> </tr> <tr> <td>Product Detail 2 </td> <td> <a class="btn btn-sm btn-success" routerLink="/product/2" routerLinkActive="active"> View </a> </td> </tr> </table>
ไฟล์ product-detail.component.html
<p> product-detail works! </p> <button class="btn" type="button" routerLink="/products">Back</button>
ในตัวอย่างโค้ด ไฟล์ product-list เราจะมีรายการ product แสดงอยู่สองรายการ พร้อมลิ้งค์ไปยังรายละเอียด
ส่วนในไฟล์ product-detail เราจะมีหน้าแสดงข้อมูลง่ายๆ พร้อมปุ่ม back ลิ้งค์กลับมายังหน้า product-list
การกำหนด Routing Module ย่อย
ต่อไปเป็นส่วนของการกำหนด routing ให้กับไฟล์ product-routing.module.ts โดยรูปแบบและวิธีการกำหนด ก็จะคล้ายๆ กับที่เรา
เคยกำหนด ในไฟล์ app-routing.module.ts ในบทความที่ผ่านมา จะแตกต่างในส่วนของการกำหนด path โดยใน routing ย่อยนี้
เราจะไม่กำหนด path ที่นอกเหนือจากการจัดการของส่วนของ product module
ไฟล์ product-routing.module.ts
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { ProductListComponent } from './product-list.component'; import { ProductDetailComponent } from './product-detail.component'; const productRoutes: Routes = [ { path: 'products', component: ProductListComponent }, { path: 'product/:id', component: ProductDetailComponent } ]; @NgModule({ imports: [RouterModule.forChild(productRoutes)], exports: [RouterModule] }) export class ProductRoutingModule { }
สังเกต บรรทัดที่ 14 ในส่วนของการ import จะเปลียนจาก forRoot เป็น forChild แทน
เนื่องจากเป็น routing ย่อย ใช้สำหรับ product module
การเรียกใช้งาน Routing ย่อยใน Module ย่อย
ส่วนต่อมาเป็นส่วนของ product module รูปแบบการใช้งาน ก็จะคล้ายกับ AppModule
ไฟล์ product.module.ts
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ProductRoutingModule } from './product-routing.module'; import { ProductListComponent } from './product-list.component'; import { ProductDetailComponent } from './product-detail.component'; @NgModule({ imports: [ CommonModule, ProductRoutingModule ], declarations: [ProductListComponent, ProductDetailComponent] }) export class ProductModule { }
บรรทัดที่ 4 5 และ 6 เป็นการ import class component และ routing module มาใช้งาน ใน product module
ส่วน commandModule ในบรรทัดที่ 10 นั้นจะเป้นส่วนที่ import เข้ามาเพื่อให้เราสามารถใช้งาน directive พื้นฐานต่างๆ
เช่น NgIf NgForOf ใน module ของเราได้
บรรทัดที่ 11 เป็นการ import ProductRoutingModule ที่เราได้สร้างไว้ เป็นส่วนของการกำหนด routing path มาใช้งานใน
NgMoudel decorator ฟังก์ชั่น
การใช้งาน Module ย่อยใน Module หลัก
หลังจากเราจัดการในส่วยของ product module เรียยร้อยแล้ว ขั้นตอนต่อไป ก็คือ การนำ module ที่เราสร้างไปใช้งานใน module หลัก
หรือ AppModule ให้เราปรับไฟล์ app.module.ts โดยจะ comment ส่วนที่ต้องตัดออก และจะ highlight สวนที่เพิ่มเข้ามา
ไฟล์ app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app-routing.module'; import { ProductModule } from './product/product.module'; import { HomeComponent } from './home/home.component'; import { UserComponent } from './user/user.component'; //import { ProductComponent } from './product/product.component'; import { PagenofoundComponent } from './pagenofound/pagenofound.component'; @NgModule({ declarations: [ AppComponent, HomeComponent, UserComponent, // ProductComponent, PagenofoundComponent ], imports: [ BrowserModule, ProductModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
บรรทัดที่ 6 เรามีการ import class product module เข้ามาใน AppModule
บรรทัดที่ 10 และ 19 ตัดส่วนของ product component ออก เนื่องจากเราไม่ได้ใช้งานโดยตรงแล้ว แต่เราจะใช้งานผ่าน
product module แทน
บรรทดัที่ 24 import product module เข้ามาใช้งานใน App หรือใน module หลัก โดยจำไว้เสมอว่า module ย่อยที่มีการกำหนด
routing ย่อยด้านใน ต้อง import ไว้ก่อน routing หลักของ App ทั้งนี้ก็เพื่อให้ routing หลักรองรับเงื่อนไขทั้งหมด กรณีเช่น
ถ้ามีการเรียกไปที่ path ที่ไม่มีการกำหนดค่า ก็ต้องผ่านเงื่อนไขของ routing หลักเป็นเงื่อนไขสุดท้ายเสมอ
และส่วนสุดท้าย ก็คือการปรับในส่วนของ routing module หลัก หรือไฟล์ app-routing.module.ts
โดยปรับส่วนที่ไม่ใช้งานออก เป็นดังนี้
ไฟล์ app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent } from './home/home.component'; import { UserComponent } from './user/user.component'; //import { ProductComponent } from './product/product.component'; import { PagenofoundComponent } from './pagenofound/pagenofound.component'; const appRoutes: Routes = [ { path: 'users', component: UserComponent }, //{ path: 'products', component: ProductComponent }, { path: 'home', component: HomeComponent }, { path: '', redirectTo: '/home', pathMatch: 'full' }, { path: '**', component: PagenofoundComponent } ]; @NgModule({ imports: [ RouterModule.forRoot( appRoutes, { enableTracing: false } // <-- debugging purposes only set true ) ], exports: [ RouterModule ] }) export class AppRoutingModule { }
จะเห็นว่าเราได้ตัดในส่วนที่เป็น component และการกำหนด path ของ product ออก ไปเนื้องจาก เรามีการกำหนด
ไว้ใน product module แล้ว
ทดสอบการทำงานได้ที่ demo ด้านล่าง เมื่อเราคลิกไปที่เมนู product ก็จะมีเรียกใช้งานผ่าน product module รวมถึงมีการใช้งาน
product routing module ในการเชื่อมโยง path เฉพาะในส่วนของ product
เนื้้อหาตอนหน้า เราจะมาดูในส่วนของการส่งค่า ผ่านการกำหนด routing path และส่วนอื่นๆ เกี่ยวกับการใช้งาน routing เพิ่มเติม
รอติดตาม