v-modelにObjectとかを指定しているとき、メソッドとかでそのObjectの要素が変わったとしても画面に反映されない時がある。そんなときの対処方法。
問題例)
<p>花子の年齢:</p><v-text-field v-model="hanako.age" readonly />
<p>年:</p><v-select items="year" v-model="selectYear" >
セレクトボックスで年を選ぶと、自動的に花子の年齢テキストボックスに年齢が表示される想定です。
export default {
data(){
return {
hanako: {},
year: [
2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,
2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
],
},
watch: {
selectYear: function(newValue) {
// 花子は2000年生まれ。
const bornYear = 2000;
// セレクトされた年-生まれ年 = 花子の年齢
this.hanako.age = newValue - bornYear;
}
}
yearをwatchで監視して値が変更される度に花子の年齢が計算されhanakoオブジェクトにageというキーで年齢を登録しています。
何も問題はなさそう。
でもこれだと、セレクトボックスから年を選んでもテキストボックスには表示されません。
一度カーソルをテキストボックスにあわせ、アウトすると表示されます。
なぜ...。
なぜかv-modelはObjectの値が変更されてもそれを画面に適用してはくれないようです。
そんな時、使うのが$set。
基本構文はこうです。
this.$set(this.someObject, 'b', 2) // (オブジェクト, キー名, 入れる値)
これを今回のソースに合わせるとこうです。
export default {
data(){
return {
hanako: {},
year: [
2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,
2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
],
},
watch: {
selectYear: function(newValue) {
// 花子は2000年生まれ。
const bornYear = 2000;
// セレクトされた年-生まれ年 = 花子の年齢
this.$set(this.hanako, 'age', newValue-bornYear);
}
}
こうすると、テキストボックスをクリックしなくても自動的に画面に反映されます。
なんでObjectだと簡単に反映されないのか、いまいちVueの仕組みが分かっていないのでちゃんとドキュメント読んで理解しないとな...。
基本的にdataプロパティーを動的に変更する場合には、$setを使った方がよさそうですね。