# 雙向數據綁定
雙向綁定語法實際上是**屬性綁定**和**事件綁定**的語法糖。 Angular 將 SizerComponent 的綁定分解成這樣:
~~~
<app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>
~~~
# 自定義雙向綁定屬性(示例):
~~~
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
@Component({
selector: 'twoway',
template: `
<input [(ngModel)]="username">
<p>Hello {{username}}!</p>
`
})
export class TwoWayComponent implements OnInit {
constructor() { }
usernameValue: string;
@Output() usernameChange = new EventEmitter();
@Input()
get username() {
return this.usernameValue;
}
set username(val) {
this.usernameValue = val;
this.usernameChange.emit(this.usernameValue);
}
ngOnInit() {
}
}
~~~
# [ngModel 內部運行機制](http://oomusou.io/angular/ngmodel/)
~~~
<select id="TDDSelect" [ngModel]="selectedId" (ngModelChange)="selectedId = $event">
<option *ngFor="let cloud of clouds" [value]="cloud.id">{{ cloud.name }}</option>
</select>
<p>{{ selectedId }}</p>
~~~
這個屬性綁定看起來很眼熟,但事件綁定看起來有點怪。
`ngModelChange`并不是 `<select>`元素的事件。 它實際上是來自`NgModel`指令的事件屬性。
**當 Angular 在表單中看到`[(x)]`的綁定目標時, 它會期待這個`x`指令有一個名為`x`的輸入屬性,和一個名為`xChange`的輸出屬性。**
模板表達式中的另一個古怪之處是`selectedId = $event`。 之前看到的`$event`對象來自 DOM 事件。 但`ngModelChange`屬性不會生成 DOM 事件 —— 它是Angular EventEmitter類型的屬性,當它觸發時, 它返回的是輸入框的值 —— 也正是希望賦給`selectedId`屬性的值。
現實中,幾乎總是優先使用`[(ngModel)]`形式的雙向綁定。 只有當需要在事件處理函數中做一些特別的事情(例如合并或限制按鍵頻率)時,才會拆分出獨立的事件處理函數
常用形式:
~~~
<select id="TDDSelect" [(ngModel)]="selectedId">
<option *ngFor="let cloud of clouds" [value]="cloud.id">{{ cloud.name }}</option>
</select>
<p>{{ selectedId }}</p>
~~~

1. 在 HTML 修改觸發 DOM 的 `change` event
2. `change` event 觸發了 Angular 的 `ngModelChange` event
3. 將 $event 傳給 `selectedId` field
4. `ControlValueAccessor` 將 `$event.target.value` 指定給 `selectedId` field
5. `selectedId` field 被修改,引發 interpolation binding 自動更新 HTML
> 步驟 4 就是將 `$event.target.value` 轉成 field 的黑魔法所在
>
# 變化檢測
由于js語言并沒有屬性變化通知的機制,所以angular也不知道誰發生了變化,在什么時候變了。Angular的變化機制是:

## 數據何時變化
主要入下集中情況可能改變數據:
用戶輸入操作,比如點擊,提交等。
請求服務端數據。
定時事件,比如setTimeout,setInterval。
這幾點有個共同點,就是他們都是異步的。也就是說,所有的異步操作是可能導致數據變化的根源因素。
## 如何通知變化
在Angularjs中是由代碼$scope.$apply()或者$scope.$digest觸發,而Angular2接入了ZoneJS,由它監聽了Angular所有的異步事件。ZoneJS重寫了所有的異步API(所謂的猴子補丁,MonkeyPatch)。ZoneJS會通知 Angular 可能有數據發生變化,需要檢測更新。
## 變化檢測原理 – 臟檢查
所謂臟檢查就是存儲所有變量的值,每當可能有變量發生變化需要檢查時,就將所有變量的舊值跟新值進行比較,不相等就說明檢測到變化,需要更新對應的視圖。
Angular的核心是組件化,組件的嵌套會使得最終形成一棵組件樹。Angular的變化檢測可以分組件進行,每個組件都有對應的變化檢測器`ChangeDetector`。可想而知,這些變化檢測器也會構成一棵樹。
另外,Angular的數據流是自頂而下的,從父組件到子組件單向流動。單向數據流向保證了高效、可預測的變化檢測,盡管檢查了父組件之后,子組件可能會改變父組件的數據使得父組件需要再次被檢查,這是不被推薦的數據處理方式。在開發模式下,Angular會進行二次檢查,如果出現上述情況,二次檢查就會報錯:ExpressionChangedAfterItHasBeenCheckedError(關于這個問題的答案,可以在參考資料中找到)。而在生產環境中,臟檢查只會執行一次。
# 參考
https://angular.cn/guide/template-syntax#two-way-binding--span-classsyntaxspan-
[Angular2雙向綁定及變化檢測](http://easywork.xin/2018/02/24/ng2-6/)
[TWO-WAY DATA BINDING IN ANGULAR](https://blog.thoughtram.io/angular/2016/10/13/two-way-data-binding-in-angular-2.html)
- PWA 概念
- Immutable
- Angular 基礎概念
- 入門參考
- Angular 更新總結
- Angular 生態系統
- Rx.js
- Ngrx
- CQRS/ES 模式
- Angular 5 詳解
- 測試
- 定義共享模塊
- 懶路由加載
- angular組件
- 雙向綁定及變化檢測
- 樣式
- ionic 3詳解
- ionic3
- ionic 插件
- Ionic 添加動畫
- Ghost-Loading
- 打包發布
- Android上架國內應用市場流程
- 總結
- 文章
- 問題合集
- Cordova
- 插件開發指南
- Android插件開發指南-官網
- IOS插件開發指南-官網
- Hooks 編寫
- 橋接技術
- ===cordova插件收集===
- 相關主題-官網
- 實戰-自定義插件流程
- UI 及 相關資源