關於 NgModel

這篇文章主要來深入討論 [(ngModel)],若你已經有在開發 Angular 2 的專案,或是自己嘗試練習 Angular 的過程中, [(ngModel)] 一定會接觸到的語法,透過[(ngModel)] 實現雙向繫結的功能,但,為什麼要使用中括號和小括號呢?

其實,繫結語法中的  [( )]  符號是一個很好的提示。

在屬性繫結中,一個值從 Model 中傳到螢幕上的目標屬性。我們把名稱放在中括號 [ ] 裡面來標記出目標屬性 。這是一個 從 Model 到 View 的單向資料繫結。

在事件繫結中,從螢幕上的目標屬性把值傳到 Model 裡。我們透過小括號 ( ) 把名稱包起來標記出目標屬性。這是一個 從 View 到 Model 的反向單向資料繫結 。

由此可知,Angular 選擇了組合符號 [( )] 來標記出雙向資料繫結和雙向資料流。

事實上,我們可以把  NgModel  繫結拆成兩個獨立的繫結,就像上一篇我們重寫的 「Name」 <input>   繫結一樣:

<input
  type="text"
  class="form-control"
  required
  [ngModel]="model.name"
  (ngModelChange)="model.name = $event"
/>
TODO: remove this: {{model.name}}

這個屬性繫結看起來很眼熟,但事件繫結看起來有點怪。

ngModelChange  並不是  <input>  元素的事件。 它實際上是一個來自  ngModel directive 的事件屬性。 當 Angular 在表單中看到一個  [(x)]  的繫結目標時, 它會預計這個  x directive 有一個名為  x  的輸入屬性,和一個名為  xChange  的輸出屬性。

樣板表達式 ( template expression ) 中的另一個奇怪的地方是  model.name = $event 。 我們以前看到的  $event  變數是來自 DOM 事件的。 但  ngModelChange  屬性不會產生 DOM 事件,它是一個 Angular 的  EventEmitter  類型的屬性,當它觸發時, return 的是輸入框的值 - 這個值剛好和我們必須設給 Model 的  name  屬性一樣。

很高興知道這些,但這樣實際嗎?實務上我們幾乎總是較習慣使用  [(ngModel)]  形式的雙向繫結。 只有當我們不得不在事件處理函式中做一些特別的事情 (例如合併或限制按鍵頻率) 時,才需要另外拆出獨立的事件處理函式。

想了解更多關於  ngModel  和其它樣板語法的內容,請參考  Template Syntax  章節。