two bindingについて
最近のマイブームはtwo-way-binding
という言葉です。その言葉の意味を簡単に説明してしまうと、参照型変数の動作です。aとb2つの変数が違うはずですが、片方に違う値を代入するともう片方の値も書き換わります。つまり、aとbは同期状態になっています。これをhtmlとjsにも同じ動作してあげると、次のような効果になります。
<span data-bind="text: a">
<input type="text" data-bind="value: a, valueUpdate: 'afterkeydown'">
違う要素のはずなのに、上記のようにaという変数をバインディングしてあげると、inputに代入されたものがspanの値はキーダウンするたびにシンクロされ、同じ値が反映されます。
最近仕事関係でknockoutJSを使って高度なバインディングをしてみました。その結果を下記にまとめました。
objectのobjectのobject... をバインディング
例として、item.category.name
についてのバインディングです。このケースはitemのcategoryが可変オブジェクトです。
itemにobserveを効いているはずですが、次のやり方だとcategoryをいくら代入しても変わってくれません。
#html
<input type="text" data-bind="value: item().category.name, valueUpdate: 'afterkeydown'">
#js
this.item = ko.observable();
// このケースだとデータが変わりますが
this.item({category: {name: "shoes"}});
// このケースだとデータが変わりません
this.item().category.name = "shoes";
なぜかというと、nameにobserveが代入されていないので、監視される変数ではないとknockoutjsが判断し、何も反映してくれません。
しかし、面白いことにjsの代入ではなく、input要素から入力するとcategoryのname変数が変わってくれます。
話が戻ると、変数が監視されるように、必ずobserveをつけなければいけません。
#html
<span data-bind="text: item().category().name">
#js
// 初期化
this.item = ko.observable({
category: ko.observable({
name:ko.observable(""),
}),
});
// データが変わります。
this.item().category().name("shoes");
valueUpdate
AngularJSをやっている人たちへ、これはkeypressするたびに変わりません。
<span data-bind="text: a">
<input type="text" data-bind="value: a">
keypressするたびに変わるにはvalueUpdateを使わないといけません。
<span data-bind="text: a">
<input type="text" data-bind="value: a, valueUpdate: 'afterkeydown'">
デフォルトとして、入力最中のテキストが変わってもバインディングされた変数が変わりません。
3つ以上異なる変数のバインディング
今回のケースはhtmlと2つ違うオブジェクトという3つの変数をバインディングするケースです。
#html
<span data-bind="text: a"> // 1つ目の変数
#js
this.a = ko.observable(); // 2つ目の変数
var objA = { a: ko.observable() }; //3つ目の変数
これらを全部シンクロさせるやり方はこれだと考えている方
#html
<span data-bind="text: a"> // 1つ目の変数
#js
this.a = ko.observable();
var objA = {a: this.a};
実はそこに罠が潜んでいます。knockoutJSのデータ更新はobservableを関数として実行する際のみです。つまり、objA.a(this.a())
はデータ更新してくれますが、上記のサンプルはobjA.a = this.a
と等しくいため、データは更新されません。
じゃ、objA.a(this.a())でやれば良いのではないかと考えている人は、また罠に引っかかりました。これは値を渡しているだけで、this.aとobjA.aはそれぞれ独立の変数になり、this.aの値が変わってもobjA.aに反映しません。objA.aの値を編集しても、this.aの値は変わりません。
var objA = {a: ko.observable(this.a())};
objA.a("first"); // this.aは"first"になりません。
this.a("second"); // objA.aは"second"になりません。