iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Modern Web

後轉前要多久系列 第 28

【後轉前要多久】# Day28 Angular - 四種資料繫結 Binding

  • 分享至 

  • xImage
  •  

Angular產生的檔案實在太多辣,我們先專注在以下三個檔案:

  • app.component.css
  • app.component.html
  • app.component.ts

先專注於這些檔案

xxx.spec.ts 是寫測試時的檔案,學習階段時看到.spec.ts都可以先忽略。

使用WebStorm IDE時,我個人會額外安裝以下這兩個套件

WebStorm IDE額外安裝套件

Component Folding 會讓同一個元件的四個檔案,以資料夾的形式(元件)來預覽
CLI QuickSwitch 則是按下 alt+S 時,在同一個元件內切換檔案(.html.css.ts)

兩個套件的功能

樣板、樣式、程式元件

範本、樣板 template

什麼是範本、樣板(template)? 就是 .html 檔案

樣式 style

什麼是樣式(style)? 就是 .css 檔案

程式、元件 component

什麼是程式、元件(component)? 就是 .ts檔案

有時後元件指的是以上三個(樣板、樣式、程式)檔案的集合體,
有時候是單純指.ts檔案。


繫結 binding

什麼是資料繫結(binding)?
資料繫結就做一件事——綁定屬性值

其中又分成單向繫結、雙向繫結

單向繫結、雙向繫結

單向繫結僅能從component把值傳給template。

在綁定成功後,數值會傳遞過去、連動修改,
可以想像成是TS丟一個變數過去給HTML吃。

而雙向繫結則是兩邊都能連動、互傳資料。

以下四種方法前三種都是單向繫結,只有最後一項是雙向繫結。

內嵌繫結 interpolation

{{property}}

app.component.html檔案內容修改為以下
HTML

<div class="container my-5">
    <h1>{{title}}</h1>
    <a href="{{url}}">{{link}}</a>
</div>

當看到兩個大括號{{}}包住的值,
Angular會先對他們做解析(如果他不處理的話,HTML會看不懂這兩個大括號在這幹嘛用的)

並在app.component.ts中設定屬性變數
TS

...
export class AppComponent {
  title = 'My Website';
  link = '前往Google';
  url = 'https://google.com';
}

內嵌繫結 interpolation

也可以在程式部分額外加上callback函式,
在兩秒後更換title文字,製造動態效果

TS

export class AppComponent {
  title = 'My Website';
  link = '前往Google';
  url = 'https://google.com';

    constructor() {
        setTimeout(() => {
            this.title = '我的網站';
        }, 2000);
    }
}

除了傳遞值,也可以在樣板中直接做運算

HTML

<p>a+b: {{a + b}}</p>

TS

...
export class AppComponent {
  a = 10;
  b = 50;
}

在樣板中直接做運算

屬性繫結 property binding

[property] = 'statement'

HTML

<div class="container my-5">
    <h1>標題</h1>
    <a [href]="url">Google連結</a>
</div>

這次不用兩個大括號了,當看到一個中括號[]包住的屬性(property),Angular會先對他們做解析(如果他不處理的話HTML也會看不懂這個中括號是在幹嘛用的)

在HTML5裡面,我們可以透過data-前綴開頭的標籤來自由定義擴充attribute。
但自定義的data-title沒辦法透過屬性繫結來做綁定,因為h1 DOM底下沒有這個property。不是所有有出現的attrubite都可以做屬性綁定

要如何查h1有哪些property?

在chrome瀏覽器中進入開發者模式檢查

最右邊這一大串,這些property都可以進行binding

那除了property以外,要如何綁定自定義的attribute呢?

內嵌繫結 <h1 data-title={{title}}}>標題</h1> 也沒辦法使用

解法:使用attr前綴來說明這是attribute屬性 [attr.data-title]=title

回頭來看,HTML確實吃到了自定義attribute

事件繫結 event binding

(event) = "method($event)"
(event) = "property=value"

此時加上一個button按鈕,將HTML稍微修改一下。
HTML

<div class="container my-5">
    <input type="button" value="更換標題">
    <h1 [attr.data-title]=title>標題</h1>
</div>

我希望點擊按鈕之後才會更換網頁大標題,可以透過Angular事件繫結做到

可以用(click)="changeTitle()"來綁定事件

HTML

<div class="container my-5">
    <input type="button" value="更換標題" (click)="changeTitle()">
    <h1>{{title}}</h1>
</div>

同時也在typesrcipt中加一個方法(method)

TS

export class AppComponent {
  title = 'My Website';
  changeTitle(){
      this.title = '更換後的標題';
  }
}

也有另一種比較不常用的做法 on-click="method()"
概念同JS的onclick事件做到

HTML

<input type="button" value="更換標題" on-click="changeTitle()">

傳入事件參數$event

透過event參數可以做到更多樣化的事

HTML

<div class="container my-5">
    <input type="button" value="更換標題 (需同時按下Ctrl)" (click)="changeTitle($event)">
    <h1>{{title}}</h1>
</div>

TS

export class AppComponent {
  title = 'My Website';
  changeTitle($event){
      if ($event.ctrlKey){
          this.title = '更換後的標題';
      }
  }
}

標註傳入參數的型別
標註為MouseEvent事件型別

changeTitle($event: MouseEvent){
    if ($event.ctrlKey){
        this.title = '更換後的標題';
    }
}

也可修改如下:
HTML

(click)="changeTitle($event.ctrlKey)

TS

changeTitle(ctrlKey: boolean){
    if (ctrlKey){
        this.title = '更換後的標題';
    }
}

雙向繫結 two-way binding

[(ngModel)] = 'property'

雙向繫結能同時做到屬性繫結()以及事件繫結[],所以符號是[()]用他來繫結某個property

HTML

<div class="container">
    <input type="text" value="" placeholder="請輸入點什麼吧" [(ngModel)]="text">
    <p>您的輸入: <span>{{text}}</span></p>
    <p>字數: <span>{{text.length}}</span></p>
</div>

TS

export class AppComponent {
    text = '';
}

回到瀏覽器上一看,就出現錯誤訊息了 Can't bind to 'ngModel' since it isn't a known property of 'input'.

看一下IDE,有出現一個提示
Can't bind to [(ngModel)] since it is not provided by any applicable directives

回到 app.module.ts 中,import FomrsModule 就可以正常使用了

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
    imports: [
        BrowserModule,
        FormsModule
    ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

看到這裡時就納悶了,為何使用到ngModel還要去import一個不相干的form模組?
原因是 NgModel
Creates a FormControl instance from a domain model and binds it to a form control element.

加上 按下ESC時清空輸入框的效果

HTML

<div class="container">
    <input type="text" value="" placeholder="請輸入點什麼吧" [(ngModel)]="text" (keyup.escape)="textReset()">
    <p>您的輸入: <span>{{text}}</span></p>
    <p>字數: <span>{{text.length}}</span></p>
</div>

TS

export class AppComponent {
    text = '';
    textReset(){
        this.text = '';
    }
}

範本參考變數 Template reference variables

與前面幾種繫結方式不同。
預設情況下,範本參考變數只能在樣板中(.html)使用

套在DOM上

直接取得DOM物件,可以在當前的template中使用
變數名稱不要與template property衝突

<div class="container">
    <input type="text" value="" placeholder="請輸入點什麼吧"
           #tText
           [(ngModel)]="text"
           (keyup.escape)="textReset()">
    <p>您的輸入: <span>{{text}}</span></p>
    <p>字數: <span>{{tText.value.length}}</span></p>
</div>

套在Directive上

Directive 就是 <app-...>
就是直接套在別的component元件上、存取該元件底下的所有property

建立一個新的元件

> ng g c header

在該元件中寫入一些HTML

<h1>Header!!</h1>

在app.component.html中加入該元件、引用進來

<div class="container">
    <app-header #tHeader></app-header>

    <input type="text" value="" placeholder="請輸入點什麼吧"
           #tText
           [(ngModel)]="text"
           (keyup.escape)="textReset()">
    <p>您的輸入: <span>{{text}}</span></p>
    <p>字數: <span>{{tText.value.length}}</span></p>

    <input type="button" value="更換標題" (click)="tHeader.title = '更改過後的標題'">
</div>

上一篇
【後轉前要多久】# Day27 Angular - 介紹
下一篇
【後轉前要多久】# Day29 Angular - 各種ng指示(ngClass、ngIf、ngFor...)
系列文
後轉前要多久30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
juck30808
iT邦研究生 1 級 ‧ 2021-10-14 12:04:46

恭喜即將邁入完賽啦~

gjlmotea iT邦研究生 5 級 ‧ 2021-10-14 21:21:06 檢舉

非常感謝支持!

我要留言

立即登入留言