はじめに
vue.jsでバインディング済みオブジェクトや配列を書き換える際に,(ビューに反映させるために)状況によってはvue.jsが用意する拡張メソッドを利用する必要があります。
結論としては「Object.$add
なりArray.$set
なり使えよ」ということになるのですが,どういうケースでこれらのメソッドを呼ぶ必要があるのかが(わたしのような)初心者にはすぐに理解できなかったので,サンプルを交えつつ紹介したいと思います。
前提コード
まず次のようなコードを考えます。
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/0.11.0/vue.min.js"></script>
<div id="container">
<div>
0: {{array[0].name}}, {{array[0].prop}}
</div>
<div v-repeat="array" v-show="$index > 0">
{{$index}}: {{name}}, {{prop}}
</div>
</div>
<script>
var app = new Vue({
el: "#container",
ready: function() {
var self = this
setTimeout(function() {
self.array[0].prop = true
self.array[1].prop = true
self.array[2].prop = true
}, 1000)
},
data: {
array: [
{ name: "a" },
{ name: "b" },
{ name: "c" }
]
}
})
</script>
ページがレンダリングされてから1秒後にapp.$data.array
が書き換えられ,最終的には次のような結果になることを期待したコードです。
0: a, true
1: b, true
2: c, true
しかしながら,実際に上記のコードを実行してみると,次のようにprop
への変更が反映されません。
0: a,
1: b,
2: c,
プロパティを追加するために$add
を呼ぶ
配列の各要素となるオブジェクトに対して,元々存在しなかったprop
というプロパティを追加している点に注目してください。このようなケースでは,ViewModelにオブジェクトのプロパティが追加されたことを知らせるために,$add
を呼んであげる必要があります。
サンプルコードのsetTimeout
呼び出し部分を次のコードに置き換えます。
setTimeout(function() {
self.array[0].$add("prop", true)
self.array[1].$add("prop", true)
self.array[2].$add("prop", true)
}, 1000)
結果は次のようになりました。
0: a,
1: b, true
2: c, true
v-repeat
を使わずに直接参照している部分がうまく動いていませんね。どのようにすれば思い通りの結果が得られるでしょうか?
配列の要素を書き換えるために$set
を呼ぶ
先ほどは直接配列の要素を参照している部分がうまく動きませんでした。どうやら,配列の特定の要素が書き換えられていることをvue.jsに教えてあげる必要がありそうです。
サンプルコードのsetTimeout
呼び出し部分を,更に次のように書き換えます。
setTimeout(function() {
var f = function(i) {
var o = self.array[i]
o.$add("prop", true)
self.array.$set(i, o)
}
f(0)
f(1)
f(2)
}, 1000)
結果は次のようになりました。
0: a, true
1: b, true
2: c, true
うまく動きました!
おわりに
今回のケースでは,$add
と$set
の両方を呼ばないと思い通りの結果を得ることができませんでした。
vue.jsでバインディング済みの配列やオブジェクトの書き換えをする場合には,これらの拡張メソッドを呼ぶ必要がないかどうか,注意を払う必要がありそうです。拡張メソッドには他の種類もあるので,詳しくは関連リンクの本家ドキュメントを読んでみてください。
動作確認環境は下記の通りです。
使用ライブラリ・ソフト | バージョン |
---|---|
vue.js | 0.11.0 |
Google Chrome | 38.0.2125.122 |
Mozilla Firefox | 33.1.1 |
どうしてこんな面倒なメソッド呼び出しが必要なのか,ということについては,関連リンクのてっく煮ブログさんに書かれているので引用します。
こんな面倒なことになっているのも、Vue.js が ECMAScript 5 の世界で頑張っているからです。
ECMAScript に提案されている Object.observe() が使える世界になれば、Object や Array の置き換えも不要になるし、Vue.js の設計もシンプルになることでしょう。