การจัดการกับ Child Routes ของ Routing ใน Angular ตอนที่ 5

เขียนเมื่อ 6 ปีก่อน โดย Ninenik Narkdee
child routes angular parammap routing angular router

คำสั่ง การ กำหนด รูปแบบ ตัวอย่าง เทคนิค ลูกเล่น การประยุกต์ การใช้งาน เกี่ยวกับ child routes angular parammap routing angular router

ดูแล้ว 9,985 ครั้ง


ในเนื้อหาตอนที่ 3 และ 4 เราได้รู้จักกับการใช้งาน child routes ในบางส่วนไปบ้างแล้ว โดยใน
product module มีการใช้งาน child routes ซึ่งเป็น route ย่อยของ route หลักที่อยู่ใน AppModule
และเนื้อหาจาก route ย่อยนี้ก็จะไปแสดงใน router outlet ของ ตัวหลัก ทบทวนได้ที่บทความด้านล่าง
    การใช้งาน Multiple Routing Module ใน Angular ตอนที่ 3 http://niik.in/843 
    การใช้งานและ การกำหนด parameter ให้กับ Routing ใน Angular ตอนที่ 4 http://niik.in/844 
 
แต่เนื้อหาในตอนต่อไปนี้ จะใช้รูปแบบที่แตกต่างออกไป เหมาะสำหรับการเพิ่มส่วนจัดการที่อาจจะไม่ค่อย
มีความสัมพันธ์กับ ตัว route หลักหรือ route อื่นๆ มากนัก เช่น อาจจะเป็น feature หรือคุณลักษณะเด่นพิเศษ
ของตัวโปรแกรมที่เพิ่มเข้ามา เป็นต้น หรือถ้าพูดแบบเข้าใจง่าย ก็คือ เหมือนเราสร้าง root component ที่คล้าย
กับ app component ขึ้นมาอีกอัน มี การใช้งาน router outlet directive ของตัวเอง และมี child route ของตัว
มันเองอีกด้วย
 
เราจะใช้รูปแบบคล้ายๆ กับ เมนู product ประกอบคำอธิบาย ดังนั้นเนื้อหา ก็จะไปแบบเร็วๆ ในที่นี้เราจะทำในส่วนของ
เมนู user จะสร้างเป็น module ใหม่ ให้เราลบโฟลเดอร์ user เดิมที่มีอยู่ออกไปแล้วสร้าง user module ใหม่ด้วยคำสั่ง
 
C:\projects\simplerouter>ng g module user --routing
 
เราจะได้ไฟล์ user.module.ts กับ user-routing.module.ts อยู่ในโฟลเดอร์ user ที่เป็น module ใหม่เพิ่มเข้ามา
 
จากนั้นเราจะสร้าง component ขึ้นมาอีก 3 component ขึ้นมาใน user module ประกอบด้วย user-center, user-list
และ user-detail สังเกตวารอบนี้ เรามีการสร้าง user-center เพิ่มเข้ามาต่างจากส่วนของ product module 
โดย user-center component นี้ เราจะใช้เป็น root ของ product module 
ให้ทำคำสั่งสร้าง component ทั้ง 3 ดังนี้
 
C:\projects\simplerouter>ng g c user/user-center --flat
C:\projects\simplerouter>ng g c user/user-list --flat
C:\projects\simplerouter>ng g c user/user-detail --flat
 
ต่อด้วยสร้าง user class กำหนดรูปแบบข้อมูลของ user ด้วยคำสั่ง
 
C:\projects\simplerouter>ng g class user/user
 
กำหนดรูปแบบข้อมูลตามนี้
 
ไฟล์ user.ts
 
export class User {
    constructor(
        public id:number,
        public firstname:string,
        public lastname:string,
        public gender:string,
        public age:number
    ){}
}
 
ต่อด้วยไฟล์ข้อมูลสำหรับทดสอบ mock users ด้วยคำสั่ง
 
C:\projects\simplerouter>ng g class user/mock-users
 
ไฟล์ mock-users.ts
 
import { User } from './user';

export var USERS:User[] = [
   {
       id:1,
       firstname:'Jubjang',
       lastname:'Phodum',
       gender:'female',
       age:24
   },
   {
        id:2,
        firstname:'Manop',
        lastname:'Phoomee',
        gender:'male',
        age:32
    },
    {
        id:3,
        firstname:'Prakit',
        lastname:'Deeprom',
        gender:'male',
        age:27       
    }

];
 
 
ต่อไปก็สร้าง service จัดการข้อมูล ด้วยคำสั่ง
 
C:\projects\simplerouter>ng g service user/user
 
ไฟล์ user.service.ts
 
import { Injectable } from '@angular/core';

import { USERS } from './mock-users';

@Injectable()
export class UserService {

  constructor() { }

  getUsers(){
    return USERS;
  }

  getUser(id:number|string){
    return USERS.filter(
      function(user,i){    
        return user.id == id ? user : null;
      }
    );    
  }

}
 
 
เสร็จในส่วนนี้แล้ว ต่อไปเราก็มาปรับในส่วนของ component ทั้ง 3 ที่ได้สร้างมาแล้วในตอนต้น เริ่มที่ user-center
อย่างที่ได้บอกไปแล้วว่า เราจะใช้ component นี้เป็น root มี router outlet ของตัวเอง ดังนั้น 
ให้เราเปิดไฟล์ user-center.component.html แก้ไขเป็นดังนี้
 
ไฟล์ user-center.component.html
 
<h3>{{title}}</h3>
<router-outlet></router-outlet>
 
จะเห็นว่ามีการใช้งาน router outlet ของตัวเอง นั่นหมายความว่า การแสดงผล coponent ต่างๆ ใน user module
จะมาแสดงใน outlet นี้ ไม่ได้ไปแสดงที่ outlet ของ app module ที่เป็น root หลัก นั่นเอง
 
 
ไฟล์ user-center.component.ts
 
import { Component, OnInit } from '@angular/core';

@Component({
//  selector: 'app-user-center',
  templateUrl: './user-center.component.html',
  styleUrls: ['./user-center.component.css']
})
export class UserCenterComponent implements OnInit {
  public title:string;
  
  constructor() { }

  ngOnInit() {
    this.title = 'User Child Routing';
  }

}
 
ไฟล์ user-list.component.html
 
<p> user-list works! </p>
<table class="table">
  <thead>
    <tr class="active">
      <th>#</th>
      <th>Firstname</th>
      <th>Lastname</th>
      <th>View</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let user of users; let i=index;" [class.warning]="highlightId == user.id" >
      <td>{{ i+1 }}</td>
      <td>{{ user.firstname }}</td>
      <td>{{ user.lastname }}</td>
      <td>
      <button type="button" routerLink="/users/{{ user.id }}"  class="btn btn-sm btn-success">
       View </button>
       </td>
    </tr>
  </tbody>
</table>
 
 
ไฟล์ user-list.component.ts
 
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

import { User } from './user';

import { UserService } from './user.service';

@Component({
//  selector: 'app-user-list',
  templateUrl: './user-list.component.html',
  styleUrls: ['./user-list.component.css']
})
export class UserListComponent implements OnInit {

  public users:User[];
  private highlightId:number|string;
 
  constructor(
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router        
  ) { }
 
  ngOnInit() {
    this.users = this.userService.getUsers();
    let params = this.route.snapshot.paramMap;
    if(params.has('id')){
      this.highlightId = params.get('id');
    }
  }

}
 
ไฟล์ user-detail.component.html
 
<p> user-detail works! </p>
<table class="table" *ngFor="let user of users">
  <tr>
    <th class="active text-right" width="120">ID</th>
    <td>{{ user.id }}</td>
  </tr>
  <tr>
    <th class="active text-right" width="120">Firstname</th>
    <td>{{ user.firstname }}</td>
  </tr>
  <tr>
    <th class="active text-right" width="120">Lastname</th>
    <td>{{ user.lastname }}</td>
  </tr>
  <tr>
    <th class="active text-right" width="120">Gender</th>
    <td>{{ user.gender }}</td>
  </tr>
  <tr>
    <th class="active text-right" width="120">Age</th>
    <td>{{ user.age }}</td>
  </tr>
</table>
<button class="btn" type="button" routerLink="/users">Back 1</button>
<button class="btn btn-info" type="button" (click)="gotoUsers()">Back 2</button>
<button class="btn btn-warning" type="button" (click)="gotoUsers2()">Back 3</button>
 
ไฟล์ user-detail.component.ts
 
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';

import { User } from './user';

import { UserService } from './user.service';

@Component({
//  selector: 'app-user-detail',
  templateUrl: './user-detail.component.html',
  styleUrls: ['./user-detail.component.css']
})
export class UserDetailComponent implements OnInit {

  public users:User[];
  private id:number|string;
   
  constructor(
    private userService:UserService,
    private route: ActivatedRoute,
    private router: Router        
  ) { }
 
  ngOnInit() {
    let params = this.route.snapshot.paramMap;
    if(params.has('id')){
      this.id = params.get('id');
    }    
    this.users = this.userService.getUser(this.id);
  }
 
  gotoUsers() {
    this.router.navigate(['/users']);
  }  
 
  gotoUsers2(){
    this.router.navigate(['/users',{id:this.id,more:'test'}]);
  }

}
 
ต่อไปให้เรากำหนด routing ให้กับ user module ที่ไฟล์ user-routing.module.ts ดังนี้
 
ไฟล์ user-routing.module.ts
 
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { UserCenterComponent } from './user-center.component';
import { UserListComponent } from './user-list.component';
import { UserDetailComponent } from './user-detail.component';

const userRoutes: Routes = [
  {
    path:'users',
    component:UserCenterComponent,
    children:[
      {
        path: '',
        component: UserListComponent
      },
      {
        path:':id',
        component:UserDetailComponent
      }

    ]
  }
];

@NgModule({
  imports: [RouterModule.forChild(userRoutes)],
  exports: [RouterModule]
})
export class UserRoutingModule { }

การกำหนด Child Routes ด้วย Chidren Property

เนื่องจาก user module มีการใช้งาน outlet ที่เป็น child จึงมีการกำหนด chidren property ให้กับ 
userRoutes และรูปแบบการกำหนด path ก็จะแตกต่างจากการกำหนด กรณีที่เป็น product จากบทความ
ที่ผ่านมา พิจารณาตัวอย่างเปรียบเทียบดังนี้
 
const productRoutes: Routes = [
  { path: 'products', component: ProductListComponent },
  { path: 'product/:id', component: ProductDetailComponent }

];
 
และ
 
const userRoutes: Routes = [
  {
    path:'users',
    component:UserCenterComponent,
    children:[
      {
        path: '',
        component: UserListComponent
      },
      {
        path:':id',
        component:UserDetailComponent
      }

    ]
  }
];
 
จะเห็นว่ากรณีของ userRoutes จะไม่ได้กำหนดเป็น users/:id เหมือนกรณีของ product เพราะ path ที่กำหนด
ใน userRoutes เป็นการกำหนดใน chridren อีกที จากรูปแบบ path ของ userRoutes จะได้ว่า
 
/users จะเป็นการไปเรียก UserCenterComponent ไปแสดงใน outlet ของ app module หลัก
โดยที่ UserCenterComponent ก็จะมี outlet ย่อยอยู่ด้วย 
ในขณะที่เรียกpath /users อยู่ outlet ย่อยใน UserCenterComponent ก็จะแสดง UserListComponent 
ไปด้วย ตามที่กำหนด ดังนี้
 
 
/users + '' ก็จะได้เป็น /users ก็จะทำให้ UserListComponent แสดงใน outlet ย่อย
และ ถ้ามีการคลิกดูรายละเอียดของ user โดยระบุ id เข้าไปใน path
/users + ':id' ก็จะได้เป็น /users:id ก็จะทำให้ UserDetailComponent แสดงใน outlet ย่อย 
 
 
ต่อไปก็เป็นการปรับไฟล์ user.module.ts , app.module.ts และ app-routing.module.ts ตามลำดับ
ตัดส่วนที่ไม่ได้ใช้งาน และนำ module ที่สร้างใหม่ไปใช้งาน เป็นดังนี้
 
ไฟล์ user.module.ts
 
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { UserRoutingModule } from './user-routing.module';
import { UserCenterComponent } from './user-center.component';
import { UserListComponent } from './user-list.component';
import { UserDetailComponent } from './user-detail.component';

import { UserService } from './user.service';

@NgModule({
  imports: [
    CommonModule,
    UserRoutingModule
  ],
  providers:[
    UserService
  ],  
  declarations: [UserCenterComponent, UserListComponent, UserDetailComponent]
})
export class UserModule { }
 
ไฟล์ app-routing.module.ts
 
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
 
 
import { HomeComponent } from './home/home.component';
import { PagenofoundComponent } from './pagenofound/pagenofound.component';
 
const appRoutes: Routes = [
  { 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 { }
 
ไฟล์ 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 { UserModule } from './user/user.module';
 
import { HomeComponent } from './home/home.component';
import { PagenofoundComponent } from './pagenofound/pagenofound.component';
  
  
@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    PagenofoundComponent
  ],
  imports: [
    BrowserModule,
    ProductModule,
    UserModule,
    AppRoutingModule // routing หลักไว้ลำดับสุดท้ายเสมอ
  ], 
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
 
ตอนนี้เราก็สามารถทดสอบการทำงาน ซึ่งเป็นการใช้งาน router outlet ซ้อนใน router outlet อีกทีแล้ว
ดูตัวอย่างได้ที่ demo 1 คลิกเลือกที่เมนู user
 
เนื้อหาในตอนนี้ ในหลักๆ แล้วจะไม่ได้มีรายละเอียดอะไรมาก แต่ต้องการนำตัวอย่างโค้ดทั้งหมดมาเป็นแนวทาง
สำหรับประกอบในตอนหน้า ซึ่งจะมีความซ้อนเพิ่มเข้ามา เช่น การใช้งาน Observable paramMap และ
การใช้งาน component reuse  รอติดตาม
 




กด Like หรือ Share เป็นกำลังใจ ให้มีบทความใหม่ๆ เรื่อยๆ น่ะครับ



อ่านต่อที่บทความ









เนื้อหาที่เกี่ยวข้อง









URL สำหรับอ้างอิง





คำแนะนำ และการใช้งาน

สมาชิก กรุณา ล็อกอินเข้าระบบ เพื่อตั้งคำถามใหม่ หรือ ตอบคำถาม สมาชิกใหม่ สมัครสมาชิกได้ที่ สมัครสมาชิก


  • ถาม-ตอบ กรุณา ล็อกอินเข้าระบบ
  • เปลี่ยน


    ( หรือ เข้าใช้งานผ่าน Social Login )







เว็บไซต์ของเราให้บริการเนื้อหาบทความสำหรับนักพัฒนา โดยพึ่งพารายได้เล็กน้อยจากการแสดงโฆษณา โปรดสนับสนุนเว็บไซต์ของเราด้วยการปิดการใช้งานตัวปิดกั้นโฆษณา (Disable Ads Blocker) ขอบคุณครับ