Week 11 · Day 07 — 實作:搜尋與篩選(第十一週收尾)

學習目標

  • 實作任務搜尋
  • 依狀態 / 分類 / 標籤篩選
  • 完成整個 MVP 專案並複習

重點

篩選狀態變數

export type Filter = 'all' | 'todo' | 'in-progress' | 'done';

filterBy: Filter = 'all';
searchTerm = '';
selectedCategory = '';

用 selector 做純函式篩選(推薦)

import { createSelector } from '@ngrx/store';

export const selectVisibleTodos = createSelector(
  selectTodos,
  selectFilter,       // { status?, category?, search }
  (todos, filter) => {
    return todos.filter(t => {
      const matchStatus =
        !filter.status || filter.status === 'all' || t.status === filter.status;
      const matchSearch =
        !filter.search ||
        t.title.toLowerCase().includes(filter.search.toLowerCase());
      return matchStatus && matchSearch;
    });
  }
);

任務列表套用

<mat-form-field>
  <input matInput placeholder="搜尋..." (input)="onSearch($event)">
</mat-form-field>

<mat-button-toggle-group [(ngModel)]="filterBy">
  <mat-button-toggle value="all">全部</mat-button-toggle>
  <mat-button-toggle value="todo">待辦</mat-button-toggle>
  <mat-button-toggle value="done">已完成</mat-button-toggle>
</mat-button-toggle-group>

<ul>
  <li *ngFor="let t of (visible$ | async)!; trackBy: trackById">{{ t.title }}</li>
</ul>

處理搜尋

onSearch(e: any): void {
  const term = (e.target as HTMLInputElement).value;
  this.store.dispatch(setSearch({ term }));   // 更新 filter state
}

建議 - 搜尋用 debounceTime 減低即時打字的負擔 - 篩選邏輯放 selector(純函式)方便測試

實作

  1. 建立 setFilter / setSearch action 更新 filter state
  2. selectVisibleTodos 同時處理狀態與關鍵字
  3. 列表套用篩選,測試「全部/待辦/已完成」交換
  4. 收尾:確認整個 MVP 流程順暢

作業

  • 用 selector 實作狀態與關鍵字篩選
  • 列表可交換篩選並搜尋
  • 完整走一遍 MVP(登入 → 建任務 → 篩選 → 完成)

總結

你已完成「任務管理系統」MVP!整合了 Angular、Material、NgRx、REST API。下一週處理上線——部署與維護。