Try   HackMD

Angular - 結構型指令:使用 ngFor 及 ngIf

ngForngIf 是屬於結構型指令的一種。

結構型指令是透過新增和刪除 DOM 元素來更改 DOM 佈局的指令,使用簡寫語法時,Angular 在一個元素上只允許有一個結構型指令

ngFor 以及ngIf很特別的是,他是可以直接撰寫在 html 當中的,這實在是很酷的一件事!

ngFor

ngFor,類似於原生 JS 的 for 循環,主要用於遍歷某個集合,並且將其值渲染到 Template 上。

首先在閱讀 Angular 文檔時,你會看見寫法是 *ngFor,前方有加了一個星號,而這個星號其實是一個語法糖,在 Angular 看見這個符號後,會自動將其轉換為 <ng-template>

<ng-template>

<ng-template> 是一個模板元素,通常在使用結構型指令時才會產生作用。

Angular's <ng-template> element defines a template that is not rendered by default. - Angular 官方。

ngFor 的基本遍歷寫法

我們會使用 <ul *ngFor = "let item of items"></ul>,由這段寫法,我們可以遍歷 items 集合,來獲取每一個 item 的值。

取得更多的值

Angular 提供了一系列的值,讓我們可以在使用 ngFor 遍歷集合時取得。
以下值可透過 Angular 官方文檔查詢到。

  1. index: number:可迭代物件中當前條目的索引。
  2. count: number:可迭代物件的長度。
  3. first: boolean:如果當前條目是可迭代物件中的第一個條目則為 true。
  4. last: boolean:如果當前條目是可迭代物件中的最後一個條目則為 true。
  5. even: boolean:如果當前條目在可迭代物件中的索引號為偶數則為 true。
  6. odd: boolean:如果當前條目在可迭代物件中的索引號為奇數則為 true。

要注意的是:first, last, even, odd 這些值都會得到布林值,而不是內容。

使用資料綁定結合 ngFor,來創建一個 todoList

創建 HTML Template

<div> <h1>TODO LIST</h1> <div class="task__input"> <!-- 這一行我們有使用到 範本參考變數、雙向綁定 --> <input #tTaskInput type="text" [(ngModel)]="taskTitle" /> <!-- 使用事件綁定來加入 task --> <button (click)="handleAddTask()">add task</button> <!-- 獲取範本參考變數的值 --> <p>{{ tTaskInput.value }}</p> </div> <!-- 使用 *ngFor 來遍歷 tasks 陣列,並取得 task 項目內容以及編號還有是否為第一個的布林值 --> <div *ngFor="let task of tasks; let i = index; let first = first"> <div class="task__item"> <span>{{ i + 1 }}</span> <input type="checkbox" /> <!-- 使用內嵌綁定來取得 task 物件的 taskTitle --> <span>{{ task.taskTitle }}</span> <!-- 判斷是否為第一個 --> <span>{{ first }}</span> <!-- 使用事件綁定來移除任務 --> <button (click)="handleRemoveTask(i)">remove</button> </div> </div> </div>

在組件中撰寫邏輯

import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { taskTitle: string = ''; /* 因為 Angular 是基於 TypeScript 所撰寫的, 所以在這裡先將 tasks 陣列中每一個 task 的物件型別給訂定, 後續也可以使用 interface 來定義物件型別*/ tasks: Array<{ taskTitle: string; isCheck: boolean; }> = []; // 當按下新增按鈕時,會增加一個任務(tasks陣列會 push 一個任務物件進入) handleAddTask() { // 如果輸入值為空,則 return if (!this.taskTitle.trim()) return; this.tasks.push({ taskTitle: this.taskTitle, isCheck: false }); this.taskTitle = ''; } // 當按下刪除按鈕時,先詢問是否刪除,是,則刪除任務 handleRemoveTask(index: any) { const isRemove = window.confirm('remove task?'); if (!isRemove) return; this.tasks.splice(index, 1); } }

angular-todolist

ngIf

ngIf,類似於原生 JS 的 If 判斷式,使用布林值來做判斷,根據 true,False,來判斷是否渲染到 Template 上。

注意:當 ngIf 返回 false 值時,該元素將從 DOM 中刪除,並且在刪除 HTML 元素時,作用域會被破壞,當元素重新放回檢視時,會建立一個新的作用域。(這部分可能會與 ngShow 來做比較)

ngIf 與邏輯運算子

在 Angular 中,使用ngIf也可以加入 &&, ||,! 這類的邏輯運算子來進行判斷。

<div *ngFor="let task of tasks; let i = index; let first = first"> <div class="task__item"> <span>{{ i + 1 }}</span> <input type="checkbox" (change)="handleChecked(i)" /> <span>{{ task.taskTitle }}</span> <!-- 使用 ngIf 來判斷是否任務已經打勾,若已經打勾則隱藏刪除按鈕 --> <button *ngIf="!task.isCheck" (click)="handleRemoveTask(i)"> remove </button> </div> </div>

ngIf 與 else

原生 JS 當中,具有 if...else 語句,當然,ngIf 也有,使用方式如下:

<div *ngFor="let task of tasks; let i = index; let first = first"> <div class="task__item"> <span>{{ i + 1 }}</span> <input type="checkbox" (change)="handleChecked(i)" /> <span>{{ task.taskTitle }}</span> <!-- 如果任務已經完成,則刪除 remove 按鈕,並且顯示 #tDone 的標籤元素 --> <button *ngIf="!task.isCheck; else tDone" (click)="handleRemoveTask(i)"> remove </button> <!-- ng-template 用於結構型指令,一般時候其內容並不會被顯示 --> <ng-template #tDone>DONE</ng-template> </div> </div>

上方程式碼使用了 *ngIf="!task.isCheck; else tDone" 來判斷任務是否已經完成,若完成,則刪除 button,改為顯示 <ng-template #tDone>DONE</ng-template>

參考資料

tags: Angular