Angular1の.component()
を使う時にbindings
でカスタムプロパティを定義することができます。その際に指定の仕方によってTwo-way bindingにするかOne-way bindingにするかを選ぶことができます。
指定の仕方の違いはbindings
オブジェクトに渡すプロパティ値を'='
にするか'<'
にするかの違いで、'='
ならTwo-way binding、'<'
ならOne-way bindingになります。
例
<!DOCTYPE html>
<html ng-app="App">
<head>
<meta charset="UTF-8">
<title>Bindings sample</title>
</head>
<body>
<app></app>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
<h1>app</h1>
Original data is : {{$ctrl.data}}
<app-child data="$ctrl.data"></app-child>
<h2>data is : {{$ctrl.data}}</h2>
<button ng-click="$ctrl.onClickButton()">Change data to current time</button>
angular.module('App', [])
// <app> の定義
.component('app', {
templateUrl: 'app.html',
controller: class {
$onInit() {
// <app> 内で data = 123 に初期化する
this.data = 123;
}
}
})
// <app-child> の定義
.component('appChild', {
templateUrl: 'app-child.html',
bindings: {
data: '=' // Two-way binding
},
controller: class {
// ボタンをクリックした時の動作。
// <app-child> 内の data を現在時刻で上書きする。
onClickButton() {
this.data = Date.now();
}
}
});
このシンプルなサンプルアプリでは<app>
,<app-child>
という二つのコンポーネントを作成し、data
という名前でデータを受け渡しています。<app-child>
内のボタンクリック時に親から受け渡されて設定されているdata
プロパティを変更します。
Two-way bindingを使用している場合、子コンポーネントでデータを変更すると、変更は親コンポーネントにも伝わります。
今度は試しにOne-way bindingにしてみましょう。変更するコードは一文字だけです。bindings
で渡す値を'='
から'<'
にします。
angular.module('App', [])
// <app> の定義
.component('app', {
templateUrl: 'app.html',
controller: class {
$onInit() {
// <app> 内で data = 123 に初期化する
this.data = 123;
}
}
})
// <app-child> の定義
.component('appChild', {
templateUrl: 'app-child.html',
bindings: {
data: '<' // One-way binding
},
controller: class {
// ボタンをクリックした時の動作。
// <app-child> 内の data を現在時刻で上書きする。
onClickButton() {
this.data = Date.now();
}
}
});
今度は子コンポーネントでdata
を変更しても、親には変更が伝わらなくなりました。
注意しなければいけないのは、One-way binding と Two-way binding で動作に違いが現れるのは、バインドしているプロパティそのものに代入する時だということです。
もしバインドしているものがオブジェクトであり、子コンポーネントでそのオブジェクトのプロパティを変更するという場合には、One-way binding でも Two-way binding でも同じように動作します。
angular.module('App', [])
.component('app', {
templateUrl: 'app.html',
controller: class {
$onInit() {
this.data = {
count: 0
};
}
}
})
.component('appChild', {
templateUrl: 'app-child.html',
bindings: {
data: '=' // '<' にしても結果は同じ
},
controller: class {
onClickButton() {
this.data.count++;
}
}
});
バインドしているのがオブジェクトである場合でも、子コンポーネントでバインドしたプロパティ自体を上書きする場合は最初の例と同じように One-way binding と Two-way binding で動作が変わります。
angular.module('App', [])
.component('app', {
templateUrl: 'app.html',
controller: class {
$onInit() {
this.data = {
count: 0
};
}
}
})
.component('appChild', {
templateUrl: 'app-child.html',
bindings: {
data: '=' // '<' にすると、親は変更されない
},
controller: class {
onClickButton() {
this.data = { count: this.data.count + 1 };
}
}
});
なぜこのような動作になるのかわからなかった方は、JavaScriptの値渡しについて調べてみましょう。
参考: http://qiita.com/migi/items/3417c2de685c368faab1
One-way binding と Two-way binding はそれぞれ必要な場面が異なります。今書いている自分のコードではどちらを使うべきかをきちんと判断して適切に使い分けるようにしましょう。