เราได้เคยใช้งาน resolve guard มาแล้วในเนื้อหาเกี่ยวกับการเรียกใช้งาน Observable ParamMap และ
การ Re-use component ในบทความตามลิ้งค์ด้านล่าง
ใช้งาน Observable paramMap และ component reuse ใน Angular ตอนที่ 6 http://niik.in/846
https://www.ninenik.com/content.php?arti_id=846 via @ninenik
โดยจะขอหยิบยกเนื้อหาในตอนนั้นมาอธิบายเพิ่มเติมเกี่ยวกับการใช้งาน resolve guard ซึ่งเหตุผลที่มีการนำ
resolve interface มาใช้งาน ก็ด้วยเพราะว่า เมื่อเราคลิกดู รายละเอียดของ user โดยไม่ผ่านการยกเลิการใช้งาน
component เดิม ทำให้เกิดการใช้งาน component ซ้ำ หรือที่เรียกว่า reuse component ทำให้ไม่สามารถเรียกดู
ข้อมูลของ user อื่นถัดจาก user แรกได้ในทันที ขออธิบายแบบเป็นการใช้งาน path ดังนี้
สมมติเราเข้าดูรายละเอียดของ user id เท่ากับ 1 ที่ path /users/1 แล้วเราก็ กด back หรือลิ้งค์กลับมาที่
/users เพื่อลือก user id ใหม่ ลักษณะแบบนี้ จะไม่เกิดการ reuse component ขึ้น เพราะมีการสร้าง component
ใหม่ทุกครั้งที่เข้าไปดูรายละเอียด user แต่ละคน แต่ถ้าเรา เข้าดูรายละเอียด user id เท่ากับ 1 ที่ path /users/1
แล้ว โดยเป็นการแสดงรายละเอียดผ่าน outlet ย่อยอีกที ทำให้เราสามารถคลิกไปดูรายละเอียด user id อื่นๆ
เช่น user id เท่ากับ 2 ได้เลย ในลักษณะแบบนี้ จะทำให้เกิด reuse component เพราะ UserDetailComponent
แสดง user id เท่ากับ 1 อยู่ก่อนหน้าแล้ว เมื่อเราคลิกไปที user id เท่ากับ 2 เลย โดยไม่มีการกดกลับไปที่ /users
ทำให้ path เปลี่ยนไปเป็น /users/2 แต่กลับพบว่า ไม่มีการแสดงข้อมูลของ user id เท่ากับ 2
ยังเป็นข้อมูลของ user id เท่ากับ 1 อยู่ ทั้งนี้ก็เพราะว่า ในขณะที่มีการเปลี่ยน path ตัว UserDetailComponent
ไม่ได้ถูกสร้างขึ้นมาใหม่ ไม่มีการส่งค่า parameter ของ user มาทำงาน ทำให้ไม่มีการดึงข้อมูลมาใหม่ สามารถดู
กรณีปัญหาดังกล่าวได้ที่ demo 1 ด้านล่าง คลิกเลือกเมนูส่วน user
ด้วยกรณีปัญหาที่เกิดขึ้นข้างต้น จึงมีการใช้งาน resolve guard เข้ามาใช้ในการดึงข้อมูลเพื่อใช้ reuse component นั้นเอง
เรามาดูรายละเอียดไปทีละส่วนกัน เมื่อมีการใช้งาน resolve ดึงข้อมูล โดยเริ่มที่ไฟล์ user-detail.component.ts
ไฟล์ user-detail.component.ts
import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, ParamMap } from '@angular/router'; import { Observable } from 'rxjs/Observable'; 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 user:User; // เดิมใช้เป็นแบบ array - public users:User[]; private id:number|string; constructor( private userService:UserService, private route: ActivatedRoute, private router: Router ) { } ngOnInit() { this.route.data .subscribe((data: { user: User }) => { this.id = data.user.id; this.user = data.user; }); } gotoUsers() { this.router.navigate(['/users']); } gotoUsers2(){ this.router.navigate(['/users',{id:this.id,more:'test'}]); } }
สังเกตในส่วนของฟังก์ชั่น ngOninit() หรือก็คือฟังก์ชั่นที่ทำงานทันทีต่อจาก constructor() เมื่อ component ถูกสร้างและ
เรียกใช้งาน
ngOnInit() { this.route.data .subscribe((data: { user: User }) => { this.id = data.user.id; this.user = data.user; }); }
การทำงานในส่วนนี้คือ ให้รอค่าจาก this.route.data ที่ถูก subscribe() การรอค่าจาก Observable ก็หมายถึงถ้าเมื่อใดก็ตาม
ตัวสังเกตการณ์ หรือ Observer ส่ง callback พร้อมค่าของข้อมูลออกมา ก็จะเข้ามาทำงานในส่วนนี้ แล้วนำค่าที่ได้ไปกำหนด
ในตัวแปร เข่นโค้ดข้างต้น ก็เอาค่า data.user.id ไปไว้ในตัวแปร id เอาค่า data.user ซึ่งเป็น object ไปไว้ในตัวแปร user เป็นต้น
โดยค่า this.route.data นั้น เป็นคาที่จากการเรียกใช้งาน resolve guard ที่ทำงานทันที่มีการเปลี่ยน path หรือก็คือ ทุกครั้งที่
มีการเปลี่ยน path เช่น จาก /users/1 ไป /users/2 หรือไป /users/3 ก็จะมีการไปเรียกข้อมูลผ่าน resolve ก่อนนั้นเอง
ต่อไปเราไปดูในส่วนของ resolve service ที่ทำงานเรียกดูข้อมูล ตามอธิบายไปข้างต้นในไฟล์ ไฟล์ user-detail-resolver.service.ts
ไฟล์ user-detail-resolver.service.ts
import 'rxjs/add/operator/map'; import 'rxjs/add/operator/take'; import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; import { User } from './user'; import { UserService } from './user.service'; @Injectable() export class UserDetailResolverService { constructor( private userService: UserService, private router: Router ) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<User> { let id = route.paramMap.get('id'); return this.userService.getUser(id).take(1).map(users => { if (users) { return users; } else { // id not found this.router.navigate(['/users']); return null; } }); } }
นี้คือ resolve service ที่ทำงานในลักษณะรูปแบบ guard service ในเนื้อหาก่อนหน้า แต่ resolve นี้จะไม่ได้คืนค่าเป็น true หรือ false
อย่างกรณี canActivate กัน canActivateChild แต่จะคืนค่าเป็นข้อมูลที่ไปดึงมาในรูปแบบ Observable โดยเมื่อมีการเปลี่บน path ตัว route
ก็จะทำการดึง id ข้อมูลที่ส่งมาใน path ผ่านคำสั่ง route.paramMap.get('id') ตามบรรทัดที่ 20 เมื่อได้ id ข้อมูลที่ต้องการหาแล้ว
ก็ใช้ userService เรียกใช้ฟังก์ชั่น getUser() โดยส่งค่า id ของ user ที่ต้องการเรียกดูข้อมูลเข้าไป ตัว operator ที่ชื่อ take() กับ map()
ของ Observable จะทำการจำกัดการทำงาน take(1) ให้หยุดที่รายการข้อมูลแรกที่ได้มา แล้วใช้ map() ดึงค่าข้อมูลมาไว้ในตัวแปร
users ตามรูปแบบโค้ดในบรรทัดที่ 22 และในบรรทัดที่ 23 ก็ตรวจสอบอีกทีว่า ถ้ามีข้อมูล users ก็ให้ return ตัวแปร users กลับออกไป
แต่ถ้าไม่มีค่า ก็ให้ลิ้งค์ไปยัง path /users
ค่าที่ return กลับออกมา จะถูกส่งไปเก็บในตัวแปรอ้างอิง ผ่านการกำหนดค่าในไฟล์ ไฟล์ 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'; import { UserDetailResolverService } from './user-detail-resolver.service'; const userRoutes: Routes = [ { path:'users', component:UserCenterComponent, children:[ { path: '', component: UserListComponent, children:[ { path:':id', component:UserDetailComponent, resolve: { user: UserDetailResolverService } } ] // end children } ] // end children } ]; @NgModule({ imports: [RouterModule.forChild(userRoutes)], providers: [ UserDetailResolverService ], exports: [RouterModule] }) export class UserRoutingModule { }
สังเกตบรรทัดที่ 22 ตัวแปร user คือ ข้อมูลที่เก็บ ค่าที่ได้มาจาก UserDetailResolverService กรณีมีข้อมูล user ที่ต้องการเรียกดู
มีการคืนค่าข้อมูลกลับมา และอย่างที่อธิบายในตอนต้น เมื่อมีการปล่อยข้อมูลออกมา การ subscribe เพื่อรอข้อมูลใน
UserDetailComponent ก็จะทำงานโดยใช้ข้อมูลจากตัวแปร user ที่ได้จากการใช้งาน resolve guard นี้ทันที ทำให้มีการแสดงรายละเอียด
ของ user id อื่นๆ ใน reuse component ได้ อย่างไม่มีปัญหา ตามตัวอย่างใน demo 2
การใช้งาน Query parameters และ Fragments
เราได้เห็นการใช้งาน route parameter ผ่านการส่งค่า parameter ระหว่าง route ไปบ้างแล้ว เช่น
http://localhost:4200/users/1 http://localhost:4200/users;id=1;more=test
เลข 1 หลัง /users/ คือ required parameter หรือ parameter ที่จำเป็นจะต้องกำหนดค่า เพื่อให้สามารถ
นำค่าไปใช้ในการดึงข้อมูลที่เกี่ยวข้องสัมพันธ์ได้ เพื่อจะดูรายละเอียดของ user ที่มี id เท่ากับ 1 ก็จะต้องระบุ
parameter ไปกับ path เป็น /users/1
ส่วน ;id=1;more=test หลัง /users คือ optional parameter หรือ parameter ที่จะมีหรือไม่ก็ได้ เป็นค่าเพิ่ม
เติมที่เราอาจจะส่งไปเพื่อใช้ในเหตุผลใดเหตุผลหนึ่งก็ได้ เช่น ในตัวอย่าง ก็ส่งค่า id ของหน้ารายการที่เพิ่งเข้าไปดู
ข้อมูลกลับมาหน้าหลักเพื่อใช้ highlight แถวของข้อมูลนั้นๆ เป็นต้น สังเกตว่า รูปแบบการใช้งาน จะไม่มีการใช้
สัญลักษณ์ & หรือ ? เหมือนกับ query string ที่เราพบทั่วไป แต่จะใช้วิธีการแบ่งแต่ละค่าด้วยเครื่องหมาย (; semicolons)
ตามตัวอย่างในวงเล็บ ( ;id=1;more=test ) ซึ่งเรียกรูปแบบนี้ว่า matrix url
Route parameter เหล่านี้จะใช้งานผ่าน ActivatedRoute service ที่เรา import เข้ามาใช้งาน
แล้ว Query parameter คืออะไร ใช้ทำอะไร ส่วนนี้เราจะมาดูกัน
เนื่องจาก route parameter จะมีการใช้งานเฉพาะ route ที่มีการกำหนดค่าเท่านั้น แล้วถ้าสมมติเราต้องการส่งค่า
parameter ที่สามารถใช้งานไปได้กับทุก route จะใช้วิธีไหน และนี้คือเหตุผลของการใช้งาน query parameter
ก็เพื่อสำหรับส่งค่า paremeter เพิ่มเติมที่สามารถใช้งานกับ route ต่างๆ ได้นั่นเอง
ส่วน Fragment นั้น จะอ้างอิงถึง element ที่กำหนดค่าที่แน่นอนในหน้าที่กำหนด โดยมีการระบุด้วย id ใช้สำหรับ
เลื่อน scrollbar ไปยังส่วนของข้อมูลในหน้าที่ลิ้งค์ไป รูปแบบที่เราพอคุ้นก็คือ เช่น #top ถ้ามีส่วนนี้ต่อท้ายใน
url ก็จะเป็นการไปยัง element ที่กำหนด id เท่ากับ top ซึ่งส่วนใหญ่ก็จะกำหนดผ่านแท็ก anchor หรือ
<a id="top"></a> แบบนี้เป็นต้น
**ก่อนมาต่อตัวอย่างและการใช้งาน query parameter และ fragment จะขอปรับโค้ดใน projects เกี่ยวกับการใช้งาน
routing โดยจะไม่มีโค้ดอธิบาย เพียงแค่ย้ายในส่วนของโค้ดของการใช้งาน canDeactivate จากเนื้อหาตอนที่แล้ว
ออกจากหน้า login ย้ายไปลิ้งค์หรือ module ไหม่ชื่อ guestbook โดยจะใช้งาน canDetactivate ในส่วนนี้แทน
กลับมาต่อการใช้งาน query parameter กันต่อ สำหรับการใช้งาน query parameter นั้น เราจะต้องทำการ import
NavigationExtras ของ angular router เข้ามาก่อนเพื่อเรียกใช้งาน
เรามาลองสมมติการใช้งานในไฟล์ auth-guard.service.ts ดังนี้
ไฟล์ auth-guard.service.ts
import { Injectable } from '@angular/core'; // import ส่วนที่จะใช้งาน guard เช่น CanActivate, CanActivateChild เป็นต้นมาใช้งาน import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot, NavigationExtras, CanActivateChild } from '@angular/router'; // import service ที่เช็คสถานะการล็อกอินมาใช้งาน import { AuthService } from './auth.service'; @Injectable() export class AuthGuardService { // inject AuthService และ Router constructor( private authService: AuthService, private router: Router) {} // กำนหนด guard ในส่วนของการใช้งานกับ canActivate canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { console.log('canActivate run'); let url: string = state.url; // เก็บ url ที่พยายามจะเข้าใช้งาน // จะผ่านเข้าใช้งานได้เมื่อ คืนค่าเป็น true โดยเข้าไปเช็คค่าจากคำสั่ง checkLogin() return this.checkLogin(url); // คืนค่าการตรวจสอบสถานะการล็อกอิน } // กำนหนด guard ในส่วนของการใช้งานกับ canActivateChild ส่วนนี้จะใช้กับ path ของ route ย่อย // ถ้าเข้าผ่าน route path ย่อย guard จะเข้ามาเช็คในส่วนนี้ก่อน กลับไปเช็คในส่วนของ canActivate() canActivateChild(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { console.log('canActivateChild run'); // จะเข้าใช้งานได้เมื่อ คืนค่าเป็น true โดยจะใช้ค่าจากการเรียกใช้คำสั่ง canActivate() return this.canActivate(route, state); } // ฟังก์ชั่นเช็คสถานะการล็อกอิน รับค่า url ที่ผู้ใช้พยายามจะเข้าใช้งาน checkLogin(url: string): boolean { // ถ้าตรวจสอบค่าสถานะการล็อกอินแล้วเป็น true ก็ให้คืนค่า true กลับอกไป if (this.authService.isLoggedIn) { return true; } // แต่ถ้ายังไม่ได้ล็อกอิน ให้เก็บ url ที่พยายามจะเข้าใช้งาน สำหรับไว้ลิ้งค์เปลี่ยนหน้า this.authService.redirectUrl = url; // redirectUrl เป็นตัวแปรที่อยู่ใน authService // จำลองค่า session id let sessionId = 123456789; // กำหนด ค่าเพิ่มเติมให้กับ NavigationExtras ที่จะมีการส่งค่าไปพร้อมกับ url // ประกอบไปด้วย query params และ fragment let navigationExtras: NavigationExtras = { queryParams: { 'session_id': sessionId }, fragment: 'anchor' }; // ลิ้งค์ไปยังหน้าล็อกอิน เพื่อล็อกอินเข้าใช้งานก่อน มีการส่งค่า query params this.router.navigate(['/login'],navigationExtras); return false; // คืนค่า false กรณียังไม่ได้ล็อกอิน } }
ดูเฉพาะในส่วนของบรรทัดที่ highlight ไว้ รูปแบบการทำงานของไฟล์นี้ คือเมื่อผู้ใช้คลิกไปยังหน้า admin ก็จะมีการเข้า
มาเช็คคำสั่ง checkLogin() และถ้ายังไม่ได้ล็อกอิน ก็จะเปลี่ยนเส้นทางไปยังหน้า login ตามรูปแบบการทำงานเดิม
แต่ในที่นี้ เรามีการส่งค่าเพิ่มไปยังหน้าล็อกอินด้วย
บรรทัดที่ 7 import NavigationExtras เพิ่มเข้ามาใช้งาน
บรรทัดที่ 46 จำลองค่าตัวแปร ที่จะส่งไปใน query params
บรรทัดที่ 50 - 53 น่าค่าตำแปรจำลองที่กำหนดไว้ มากำหนดในค่า navigation object ที่ประกอบไปด้วย
query params และ fragment
บรรทัดที่ 56 navigation object ไปใช้งานในฟังก์ชั่น navigate() โดยส่งค่าไปกับ url
รูปแบบ url ของการส่งค่าข้างต้นเมื่อมีการเปลี่ยนเส้นทางไปยังหน้า login จะเป็นดังนี้
http://localhost:4200/login?session_id=123456789#anchor
โดย session_id=123456789 คือ key และ value ของ query params
ส่วน fragment จะแยกด้วย # ตามด้วยชื่อ fragment ที่เรากำหนด
สมมติเราไม่ต้องการส่งค่า fragment ไปด้วย ก็สามารถกำหนดเฉพาะ queryParams ก็ได้ เช่น
let navigationExtras: NavigationExtras = { queryParams: { 'session_id': sessionId } };
url ก็จะเหลือแค่
http://localhost:4200/login?session_id=123456789
และไม่มีการเลื่อน scrollbar หน้าเพจที่แสดง ไปยัง fragment เพราะไม่มีการกำหนดค่า
หรือกรณีเราต้องการส่งค่าแบบหลายๆ ค่าสมมติเป็นดังนี้
let queryData = { data1:1, data2:'test' }; let navigationExtras: NavigationExtras = { queryParams: queryData, fragment: 'anchor' };
ก็จะได้ url เป็นดังนี้
http://localhost:4200/login?data1=1&data2=test#anchor
รูปแบบลักษณะนี้ คิดว่าคงจะคุ้นตากันดี สามารถดูการใช้งานเพิ่มเติมได้ที่
เราสามารถคงค่า query params และ fragment ที่ถูกส่งมาครั้งแรกให้ใช้งานต่อในหน้าที่จะมีการเปลี่ยนเส้นทางไป
ได้ โดยไม่ต้องกำหนดค่าใหม่ได้ดังนี้ ในที่นี้เมื่อผู้ใช้คลิก admin ก็จะลิ้งค์ไปหน้า login พร้อมกับ query params
แล้วเมื่อผู้ใช้กด login เราจะให้ค่า query params นี้ถูกส่งค่าไปต่อยังหน้า admin โดยกำหนดในไฟล์
login.component.ts ก่อนลิ้งค์ไปหน้า admin ดังนี้
ไฟล์ login.component.ts
import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, NavigationExtras, ParamMap } from '@angular/router'; import { Observable } from 'rxjs/Observable'; // import AuthService สำหรับตรวจสอบสถานะการล็อกอินมาใช้งาน import { AuthService } from '../auth.service'; import { DialogService } from '../dialog.service'; @Component({ //selector: 'app-login', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent implements OnInit { public loginMessage:string; // กำหนดตัวแปรสำหรับเก็บข้อความบอกสถานะการทำงาน // injext AuthService และ Router มาใช้งาน constructor( private authService:AuthService, private router:Router, private dialog:DialogService ) { } // ฟังก์ชั่นนี้ เป้นคนละตัวกับคำสั่ง login() ใน AuthService ตัวนีจะทำงานเมื่อผู้ใช้คลิกที่ปุ่ม submit // เป็นฟังก์ชั่นที่ทำงานในหน้าล็อกอิน เมื่อสมมติผู้ใช้กรอกช้อมูลเรียบร้อยแล้ว และกดปุ่มล็อกอิน login(){ // แสดงข้อความผ่านตัวแปร dddd ว่ากำลังพยายามล็อกอิน เนื่องจากเราใช้วิธีการ delay สถานะการล็อกอิน // ในไฟล์ auth.service.ts ข้อความนี้จึงแสดงอยู่ภายใน 3 วินาที this.loginMessage = 'Trying to log in ...'; // เนื่องจากค่า true ที่เรา delay เป็น Observable เราต้องทำการ subscribe // รอค่าที่ Observable จะส่งออกมา this.authService.login().subscribe(() => { // เมื่อมีการส่งค่ากลับมา และเป็น true แสดงว่ามีการล็ฮกอินแล้ว if (this.authService.isLoggedIn) { // ดึงค่า url ที่พยายามเข้าใช้งานก่อนล็อกอิน มากำหนดหน้าที่จะลิ้งค์ไป // ถ้าไม่มีค่ากำหนดเป็นค่าหน้าหลักที่ต้องการ ในที่นี้กำหนดว่า ถ้าไม่มีค่าให้ไปที่ /admin let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/admin'; // การกำหนดค่า แบบให้คงค่าเดิม ทัืง query params และ fragment let navigationExtras: NavigationExtras = { queryParamsHandling: 'preserve', preserveFragment: true }; // ลิ้งค์ไปยังหน้าที่กำหนด this.router.navigate([redirect],navigationExtras); } }); } // ฟังก์ชั่นนี้สร้างให้กับปุ่ม cancel แต่ในที่นี้ไม่ได้ทำอะไรพิเศษ cancel(){ console.log('Cancel'); } ngOnInit() { } }
ดูในส่วนของ highlight เมื่อผู้ใช้ ล็อกอินเข้ามาก็จะลิ้งค์ไปหน้า admin พร้อมกับส่งค่า query params และ
fragment ค่าเดิมต่อไปใช้งานในหน้า admin ด้วยตามรูปแบบ url ดังนี้
http://localhost:4200/admin?session_id=123456789#anchor
ทีนี้เรามาลองดึงค่ามาใช้งานหรือมาแสดง ในหน้า admin ซึ่งเราจัดการในไฟล์ admin-center.component.html
เพื่อแสดงข้อมูลค่าจาก query params ดังนี้
ไฟล์ admin-center.component.html
<p> admin-center works! </p> <p>Session ID: {{ sessionId | async }}</p> <a id="anchor"></a> <p>Token: {{ token | async }}</p> <button [routerLink]="['/admin']" routerLinkActive="btn-info" [routerLinkActiveOptions]="{ exact: true }" class="btn btn-sm btn-default" >Home</button> <button [routerLink]="['/admin/users']" routerLinkActive="btn-info" class="btn btn-sm btn-default" >Manage User</button> <button [routerLink]="['/admin/products']" routerLinkActive="btn-info" class="btn btn-sm btn-default" >Manage Product</button> <button class="btn btn-sm btn-danger" (click)="logout()" type="button">Log Out</button> <router-outlet></router-outlet>
และกำหนดวิธีการรับค่าในไฟล์ admin-center.component.ts เพื่อนำไปแสดงในไฟล์ admin-center.component.html
ตามโค้ดด้านบนดังนี้
ไฟล์ admin-center.component.ts
import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute, ParamMap } from '@angular/router'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map'; import { AuthService } from '../auth.service'; @Component({ //selector: 'app-admin-center', templateUrl: './admin-center.component.html', styleUrls: ['./admin-center.component.css'] }) export class AdminCenterComponent implements OnInit { // กำหนดตัวแปร สำหรับเก็บค่า qeury params ที่ส่งมา ใช้เป็นแบบ Observable public sessionId: Observable<string>; public token: Observable<string>; constructor( private authService:AuthService, private route: ActivatedRoute, private router:Router) { } // คำสั่ง สำหรับเรียกให้ AuthService ทำคำสั่งล็อกเอาท์อีกที logout() { this.authService.logout(); this.router.navigate(['/login']); // หลังจากล็อกอาท์ให้ไปที่หน้าล็อกอิน } ngOnInit() { // เก็บค่า session ID ถ้ามี ถ้าไม่มีให้ขึ้นคำว่า None this.sessionId = this.route .queryParamMap .map(params => params.get('session_id') || 'None'); // เก็บค่า fragment ถ้ามี ถ้าไม่มีให้ขึ้นคำว่า None this.token = this.route .fragment .map(fragment => fragment || 'None'); } }
ในส่วนของการนำค่าไปแสดงผล เนื่องจากข้อมูลที่เรากำหนดเป็น แบบ Observable เราจะเป็นต้องกำหนด
| async ในบรรทัดที่ 2 และ 4 เข้าไปด้วย เพื่อระบุว่าเป็นข้อมูลที่เกิดทีหลัง หรือข้อมูลที่ถูกปล่อยหรือส่งมาภายหลัง
สามารถดูการทำงานได้ที demo 3 หากต้องการดู url ด้วย ให้ดูผ่าน ลิ้งค์นี้
เนื้อหาเกี่ยวกับ routing ตอนนี้ก็ใกล้จะจบแล้ว เหลืออีกไม่กี่ตอน รอติดตามตอนหน้าต่อไป