Angular Router

·

5 min read

Các câu hỏi với Router

1. Sự khác nhau giữa forRoot và forChild

  • forRoot: Khi gọi forRoot thì Angular sẽ tạo 1 instance của Router để hoạt động trong toàn bộ ứng dụng và angular cũng chỉ cần 1 instance của Router trong toàn bộ app, forRoot sẽ được gọi trong app-routing.module.
  • forChild: Khi gọi forChild, ta chắc chắn đã có 1 instance của Router rồi và nói với angular rằng hãy đăng kí các routes này với instance của Router đó.

2. RouterLinkActive

  • Có thể dựa vào directive này để set class highlight link.

3. Default Route

  • VD:
export const appRoutes: Routes = [
        { path: 'home', component: HomeComponent },
        { path: '', redirectTo: 'home', pathMatch: 'full' },
        { path: '**', component: ErrorComponent }];
  • Đây là default route: { path: '', redirectTo: 'home', pathMatch: 'full' } => Dùng khi người dùng k nhập gì vào link - đường dẫn lúc đấy sẽ là '/', khi này router sẽ redirect đến home, patchMatch để nó hiểu là đường dẫn phải chính xác tuyệt đối là '' (url = ''), bởi với bất kì đường dẫn nào cũng kết thúc = '' nên cần có patchMatch.

4. Wild Card Route

  • Đây là wild card route: { path: '**', component: ErrorComponent } => Nghĩa là khi không có đường dẫn nào khớp với tất cả những đường dẫn trên nó thì nó sẽ trả về ErrorComponent.

    Lưu ý: Router sẽ tìm kiếm route nào khớp đầu tiên và render component ra, do đó cần đặt wild card route ở cuối routes

5. Pass parameter

  • { path: 'product/:id', component: ProductDetailComponent } => đường dẫn này sẽ khớp với url: /product/1 , /product/2 ... hoặc <a [routerLink]="['/Product', ‘2’]">{{product.name}} </a>

6. Snapshot vs Observable

  • Snapshot: dùng khi chỉ cần lấy giá trị khởi tạo:
    this.id=this._Activatedroute.snapshot.paramMap.get("id");
  • Observable: dùng khi cần lấy giá trị thay đổi theo thời gian `this._Activatedroute.paramMap.subscribe(params => {

    this.id = params.get('id'); 
    

    });`

    Nguyên nhân: Thường các giá trị như id trên ta sẽ lấy trong OnInit, mà khi người dùng di chuyển đến 1 component, nếu 1 instance của component đã tồn tại, nó sẽ dùng lại component này nên khi đấy nó sẽ không chạy vào OnInit nữa => nếu dùng Snapshot thì id sẽ không được cập nhật, còn nếu dùng Observable => giá trị mới sẽ luôn được cập nhật khi id thay đổi. Khi dùng Observable nhớ đưa vào subscription và unsubscribe nó.

7. Guard

  • Dùng để quản lí, cho phép/ không cho phép/ xử lí trước khi vào/ra 1 url nào đó, có 5 loại guard.

    a. CanActivate

  • Thằng này sẽ check và cho phép truy cập vào link không, ví dụ trước khi vào màn nào đấy thì phải đi qua 1 màn khác hoặc click link, button chứ không được gõ trực tiếp url.

VD:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot,RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthGuardService implements CanActivate {

  constructor(private _router:Router ) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree | {
     if (condition)  {
          alert('You are not allowed to view this page');
          return false;
      } 
      return true;
  }
}

routes: { path: 'product', component: ProductComponent, canActivate : [AuthGuardService] }

return true => người dùng so quyền truy cập, return false => người dùng không có quyền truy cập.

b. CanDeactivate

  • Xử lí khi user rời khỏi component, thường dùng trong TH user chưa save data mà muốn rời component thì sẽ hiển thị confirm.

    VD:

import { Component } from `'@angular/core'`;

@Component({
  templateUrl: "register.component.html",
})
export class RegisterComponent    

     //Check if there any unsaved data etc. If yes then as for confirmation 
    canExit() : boolean {
    if (confirm("Do you wish to Please confirm")) {
        return true
      } else {
        return false
      }
    }
}
import { Injectable } from `'@angular/core'`;
import { CanDeactivate } from `'@angular/router/src/utils/preactivation'`;
import { ActivatedRouteSnapshot, RouterStateSnapshot } from `'@angular/router'`;
import { Observable } from 'rxjs';
import { RegisterComponent } from './register.component';

@Injectable()
export class DeactivateGuard implements CanDeactivate {

  component: Object;
  route: ActivatedRouteSnapshot;

  canDeactivate(component:RegisterComponent,
                  route: ActivatedRouteSnapshot, 
                  state: RouterStateSnapshot,
                  nextState: RouterStateSnapshot) : Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
          return component.canExit();
    }
  }

routes: { path: 'register', component: RegisterComponent, canDeactivate:[DeactivateGuard] }

nếu canDeactivate trả về true => redirect tới next route, ngược lại sẽ ở lại component này.

c. Resolve

  • Trì hoàn việc navigate (delay) để làm gì đó xong mới di chuyển đến route.

d. CanLoad

  • Giống CanActivate nhưng canDeactive vẫn tải module về trình duyệt còn thằng này thì sẽ không tải module đấy về nên sẽ không có cách nào truy cập vào, thích hợp khi dùng để phân quyền user.

    VD:

import { Injectable }       from `'@angular/core'`;
import { CanLoad, Route, Router } from `'@angular/router'`;

@Injectable()
export class AuthGuardService implements CanLoad {

  constructor(private router: Router) {}

  canLoad(route: Route): boolean {

    let url: string = route.path;
    if (url === 'admin') {
      alert('You are not authorised to visit this page');
      return false;
    }  
    return true; 
  }
}

routes: {path: "admin", loadChildren:'./admin/admin.module#AdminModule', canLoad:[AuthGuardService]}

e. CanActivateChild

  • Cho phép kích hoạt 1 child route hay không.

    VD:

import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot,RouterStateSnapshot } from '@angular/router';

@Injectable()
export class AuthGuardService implements CanActivateChild {

      constructor(private _router:Router ) {}

      canActivate(route: ActivatedRouteSnapshot,
                  state: RouterStateSnapshot): boolean {
          if (condition)  {
              alert('You are not allowed to view this page');
              //redirect to login/home page etc
              //return false to cancel the navigation
              return false;
          } 
          return true;
      }
  }
  routes:
  { path: 'product', component: ProductComponent, canActivate : [AuthGuardService], 
    canActivateChild : [AdminGuardService],
          children: [
          {  path: 'view/:id', component: ProductViewComponent  },
          {  path: 'edit/:id', component: ProductEditComponent  },
          {  path: 'add', component: ProductAddComponent }
          ]  
      }

8. Tham khảo

https://www.tektutorialshub.com/angular-tutorial/#angular-router.