6-5.Angular 入門教學 - 使用路由參數取得指定內容

Angular 入門教學


通常我們去某個文章的頁面,文章的版面都會是一樣的,只有內容不一樣

這個時候網址會是後面帶一個該文章的主鍵ID,例如:/content/主鍵ID

然後我們程式在依據這個ID取得對應的內容,那在Angular裡要如何取得這個ID呢?

這邊已經我先把必要的頁面先做好了,如果要照著範例做,可以先下載初始範例檔

這個範例要來示範,我這邊會有很多待辦事項主題,各個主題會有自己的代辦事項

這邊我先做好了三個主題,之後點進去後要分別取得自己的代辦事項

那這邊有做了一支新的API(todo6_5),因為多了一個群組的概念,傳遞的參數也會有所不同,所以我們要先改一下todo-api.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Todo } from '../@models/todo.model';

@Injectable({
  providedIn: 'root'
})
export class TodoApiService {
  private url = '/api/todo6_5';

  constructor(private http: HttpClient) { }

  取得資料(id: string) {
    return this.http.get<Todo[]>(this.url + '/' + id);
  }

  新增(value: Todo) {
    return this.http.post<Todo>(this.url, value);
  }

  修改(value: Todo) {
    return this.http.put(`${this.url}/${value.TodoId}`, value);
  }

  刪除(value: Todo) {
    return this.http.delete(`${this.url}/${value.TodoId}`);
  }

  全部狀態統一(value: boolean, id: string) {
    return this.http.put(`${this.url}/Status/${id}/${value}`, null);
  }

  刪除已完成事項(id: string) {
    return this.http.delete(`${this.url}/clearCompleted/${id}`);
  }

}

那其他地方有使用到以上修改的參數也要先做一些修改,程式才能運作,這邊大家可以先試著看著錯誤訊息找到要修改的地方

todo.service.ts

import { Injectable } from '@angular/core';
import { Todo, TodoClass, TodoStatusType } from '../@models/todo.model';
import { TodoApiService } from './todo-api.service';

@Injectable({
  providedIn: 'root'
})
export class TodoService {
  toggleAllBtn = false;
  nowTodoStatusType = TodoStatusType.All;
  todoDataList: Todo[] = [];
  gid = '';

  get nowTodoList() {
    let list: Todo[] = [];

    switch (this.nowTodoStatusType) {
      case TodoStatusType.Active:
        list = this.todoActive;
        break;
      case TodoStatusType.Completed:
        list = this.todoCompleted;
        break;
      default:
        list = this.todoDataList;
        break;
    }

    return list;
  }

  get todoActive(): Todo[] {
    return this.todoDataList.filter(data => !data.Status);
  }

  get todoCompleted(): Todo[] {
    return this.todoDataList.filter(data => data.Status);
  }

  constructor(private todoApiService: TodoApiService) { }

  getData() {
    this.todoApiService.取得資料(this.gid).subscribe(data => {
      this.todoDataList = data;
      this.ready();
    });
  }

  ready() {
    this.todoDataList.forEach(data2 => {
      data2.CanEdit = true;
      data2.Editing = false;
    });
    this.checkToggleAllBtn();
  }

  add(value: string) {
    const seqno = new Date().getTime();
    const todo: Todo = new TodoClass(value, false, seqno);
    todo.GroupId = this.gid;
    this.todoDataList.push(todo);
    this.todoApiService.新增(todo).subscribe(data => {
      this.todoDataList.forEach(data2 => {
        if (data2.Seqno === seqno) {
          data2.TodoId = data.TodoId;
          data2.CanEdit = true;
        }
      })
    });
  }

  update(item: Todo) {
    this.todoApiService.修改(item).subscribe();
    item.Editing = false;
  }

  clickCheck(item: Todo) {
    item.Status = !item.Status;

    this.todoApiService.修改(item).subscribe();
    this.checkToggleAllBtn();
  }

  delete(item: Todo) {
    this.todoApiService.刪除(item).subscribe();
    this.todoDataList = this.todoDataList.filter(data => data !== item);
  }

  toggleAll() {
    this.toggleAllBtn = !this.toggleAllBtn;
    this.todoDataList.forEach(data => {
      data.Status = this.toggleAllBtn;
    });

    this.todoApiService.全部狀態統一(this.toggleAllBtn, this.gid).subscribe();
  }

  clearCompleted() {
    this.todoApiService.刪除已完成事項(this.gid).subscribe();
    this.todoDataList = this.todoActive;
  }

  checkToggleAllBtn() {
    if (this.todoCompleted.length === this.todoDataList.length) {
      this.toggleAllBtn = true;
    } else {
      this.toggleAllBtn = false;
    }
  }

  setTodoStatusType(type: number) {
    this.nowTodoStatusType = type;
  }


}

接著我們看到路由的設定,這邊我已經先寫好了

todo-routing.module.ts

const routes: Routes = [
  { path: 'list', component: TodoListComponent },
  { path: 'content/:id', component: TodoContentComponent },
  { path: '', redirectTo: 'list', pathMatch: 'full' }
];

其中:id,就是準備要傳參數的地方的寫法,一個:加上自訂變數

接著我們就要到todo-list.component.html改一下參數的網址

<div class="cen">代辦事項列表</div>
<div class="mar5" *ngFor="let item of dataList">
  <a [routerLink]="['../content',item.GroupId]" type="button" class="btn btn-outline-primary">
    {{item.Name}}
  </a>
</div>

接著我們就要到todo-content.component.ts中來取得Id,那這邊會注入一個ActivatedRoute,一個可以取得參數的服務

constructor(private todoService: TodoService,private route: ActivatedRoute) { }

然後我們在init中去訂閱取得

ngOnInit() {
  this.todoService.todoDataList = [];
  this.route.paramMap.subscribe(data => {
    this.todoService.gid = data.get('id') as string;
    this.todoService.getData();
  });
}

其中data.get('id')的id就是我們路由中自訂的參數名稱,後面有個as string 是因為有可能是null,為了讓編譯可同過強行轉string

接著我們進到todo頁面就可以看到todo的代辦事項了

而其他兩個,則不會有內容,我們可以分別在不同的代辦事項新增東西是否能成功運作

那基本上沒什麼問題,接著再教另一種取得的方式如下

ngOnInit() {
  this.todoService.todoDataList = [];
  this.todoService.gid =this.route.snapshot.paramMap.get('id') as string;
  this.todoService.getData();
}

但這個用法要小心,如果擺在ngOnInit裡,是初始化才會執行,如果你是在這一頁直接轉換不同id的這一頁

將不會執行ngOnInit,而不會執行,就不會取到正確的資料,用講得不好講,影片會示範

而訂閱的方式只要數值有變更,就會執行,所以不會有這個問題

 

範例檔:下載




Copyright © 凱哥寫程式 2022 | Powered by TalllKai ❤