Angular 4:Data Binding




Angular data bnding 有以下幾種data binding方式:


String Interpolation
String Interpolation是可以將程式的變數輸出至template中顯示,使用方式是將變數或是function放在{{ 變數/function }},即可讓變數顯示在template上。
在class中,定義變數:
export class ServerComponent {
    serverId: number = 10;
    serverStatus: string = "offline";

    getServerStatus() {
        return this.serverStatus;
    }
}

class中有serverId與serverStatus兩個變數,於是在template內可以使用string interpolation的方式來顯示,分別使用變數與function呈現:
<p>Serve with ID {{serverId}} is {{getServerStatus()}}</p>
將定義的變數放置在{{}}內,開啟網頁,即可看見結果將serverId與serverStatus顯示出來:

Attribute Binding

要以變數或是function執行結果來控制html element屬性時,可以使用attribute binging,例如要控制一個button是否被disabled,就可以透過button的其中一個屬性:disabled來達到控制的效果,我們只要想辦法控制disabled屬性的value即可達到這效果,因此可以透過attribute binding的方式來控制該屬性,attribute binding是以[屬性名稱] 中括弧將element的屬性包起來:
例如以下template呈現方式:
<button class="btn btn-primary" [disabled]="!allowNewServer">Add server</button>

透過allowNewServer變數,來決定button是否被disabled,同時在程式內也得宣告變數allowNewServer才會有效

export class ServersComponent {

  allowNewServer = false;

  constructor() {
    setTimeout(() => {
      this.allowNewServer = true;
    }, 2000)

  }

}

透過這程式,一開始宣告allowNewServer為false,在button的disabled上邏輯是!allowNewServer,等同於button的disable=true,表示button為不可點擊的狀態,這邊設了一個timeout,表示在兩秒後將allowNewServer的值改為true,讓button變為可點擊的狀態,因此,attribute binding即是將Html Element的屬性與Angular變數做結合,讓變數改變的同時,Html Element的屬性也一起改變,同時立即呈現到使用者眼前。

同理,要改變<p>的內文也用attribute binding的方式:
<p [innerText]="contentToDisplay"></p>
即可在變數改變時,同時改變<p>的文字內容。

Event Binding

Event Binding是將Html Element的event與Angular內的function做綁定,讓html element在觸發特定事件時,可以執行Angular程式碼,舉例來說,像是button的onclick,要讓button的onclick觸發時,執行特定Angular程式碼。
Angular Event Binding的方式是用括弧將event名稱包起來,像是 (click)=functionName。

簡單做個測試:
在程式碼內新增一個string:serverCreationStatus,與一個function,當function觸發時,就改變serverCreationStatus並顯示在畫面上:

程式碼:
  serverCreationStatus: string = 'No server was created.';
  onCreateServer() {
    this.serverCreationStatus = 'Server was created.';
  }

template的部分:
<button class="btn btn-primary" [disabled]="!allowNewServer" (click)="onCreateServer()">Add server</button>
<p>{{serverCreationStatus}}</p>

這邊在button的click事件上綁定了onCreateServer事件,只要點擊button後就會執行onCreateServer 的function,並且改變serverCreatonStatus,畫面上的文字也會改變。

考慮一個情境,讓使用者輸入文字,作為serverName,每當使用變更input 內容時,就同時改變serverName的值。步驟依序如下:

新增input html element,

<input class="form-control" (input)="onUpdateServerName($event)type="text">
並且綁定input事件,在使用者變更input content時,都會執行onUpdateServerName事件,同時傳入$event變數,$event變數是保留變數,主要是傳入當下觸發的事件資訊到onUpdateServerName function中。

調整程式碼如下:

export class ServersComponent implements OnInit {

  allowNewServer = false;
  serverCreationStatus: string = 'No server was created.';
  serverName: string = '';

  constructor() {
    setTimeout(() => {
      this.allowNewServer = true;
    }, 2000)

  }

  onCreateServer() {
    this.serverCreationStatus = 'Server was created.';
  }

  onUpdateServerName($eventEvent) {
    console.log($event);
    this.serverName = (<HTMLInputElement>$event.target).value;
  }

  ngOnInit() {
  }

}

在onUpdateServerName function中,可以把$event印出來看看,可以看到詳細資訊,



 打開console可以看見傳入的是一個event物件,其中有一個target就是目標html的資訊,展開來可以看到觸發事件的html詳細資訊:

到最下面可以看到value屬性,指的就是input輸入的內容,同時可以注意到_proto_是HTMLInputElement,表示觸發的html element型態。

在程式碼內因為要取得input element的內容,所以必須取用$event.target.value,即使用者輸入的內容,只是typescript會有警告,

原因是$event.target型態是EventTarget,EventTarget並沒有value的attribute的,要找到value,則必須把$event.target cast成 上面_proto_寫的HTMLInputElement型態,就可以成功拿到value值了。

所以要在程式碼調整成以下方式即可。
(<HTMLInputElement>$event.target).value;


取得使用者輸入資訊後,立刻指定給serverName,並且在template上加入{{serverName}},即會立刻輸出使用者輸入之內容。


Two-Way-Binding

前一個Event binging是使用者輸入資料時,可以讓輸入的資料與Angular內變數作連動,即資料變更時,Angular內的變數值也會跟著異動,只是若在程式內調整了變數的值,在使用者輸入介面上並不會呈現出來。
例如前一個event binding程式:
template:
<input class="form-control" (input)="onUpdateServerName($event)type="text">
<p>Server Name: {{serverName}}</p>

typescript部分調整onUpdateServerName方法,變成在取得新的數值後,加入 " Edit"字串。
 onUpdateServerName($eventEvent) {
    this.serverName = (<HTMLInputElement>$event.target).value;
    this.serverName = this.serverName + ' Edit';
  }

執行後會發現,input輸入資料時,Angular的變數有改變,但是Angular變數做修改時,input處的資料卻還是原本的資料。



Two-way binding則可以處理這部分的問題,當使用者在input內輸入資料時,Angular的資料會連動,同時Angular對該資料作處理與調整後,同時也會連動到前端input的資料上。
使用方式是[(ngModel="變數名稱")],在允許使用者輸入的element上可以使用,除了可以將使用者輸入帶到Angular程式邏輯外,Angular程式內所作的調整也會同步顯示到input上。

可以做個比較:
上面的input使用event bingind,下面的input使用two-way binding,再透過string interpolation觀察Angular內serverName變化,結果如下:

在第一個input1輸入數值1234後,Angular程式調整了serverName的內容變為1234 Edit,input1仍維持原本的輸入結果,input2則與Angular內的變數同步了,顯示1234 Edit。


template:
<input class="form-control" (input)="onUpdateServerName($event)type="text">
<input type="textclass="form-control" [(ngModel)]="serverName">
<button class="btn btn-primary" [disabled]="!allowNewServer" (click)="onCreateServer()">Add server</button>
<p>Server Name: {{serverName}}</p>

typescript:
  serverName: string = '';
  onUpdateServerName($eventEvent) {
    this.serverName = (<HTMLInputElement>$event.target).value;
    this.serverName = this.serverName + ' Edit';
  }


要使用two-way databinding,一定要確認ngModel可以使用,所以要做的事情是確認app,modules.ts檔案內,imports陣列有加入FormsModule,同時也要將@angular/forms import到app.module.ts檔案中
import { FormsModule } from '@angular/forms';  //別忘記將forms import進來
.
.
.

imports: [
    BrowserModule,
    FormsModule,     //一定要import才能使用two-way data binding
    HttpModule
  ],







1 則留言:

  1. 我也在学这门课 坚持更新呀 你写得太好了!!

    回覆刪除

Java Spring Framework 筆記 - Autowiring (2)

這篇記錄透過 Annotation來做到 Spring的 autowiring。