Help us understand the problem. What is going on with this article?

KnockoutJSの細かすぎて伝わらないtwo way bindingのネタ帳

More than 3 years have passed since last update.

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"になりません。
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away