はじめに
わかってしまえば簡単なことなのだが、
当時は解決に時間を要したので備忘録として残します。
やりたきこと
こんな感じのテーブルにて
チェックボックスをOFFにした際、確認ダイアログを表示する。
OKならそのままチェックボックスはOFFに、
キャンセルならチェックボックスはONのままに留めたい。
詰まったこと
確認ダイアログでキャンセルを選択してもチェックボックスがOFFになってしまう。
キャンセルしてもOFFになってしまう問題が出ていた時の実装が↓こちら。
実装(html)
<divid="app"><table><thead><tr><th>メールアドレス</th><th>ユーザ名</th><th>表示</th></tr></thead><tbody><trv-for="(item, index) in mailList":key="item.email"><td>{{item.email}}</td><td>{{item.name}}</td><td><inputtype="checkbox"name="checkbox"v-model="item.dispFlg"@click="onClick(index)"></td></tr></tbody></table></div>
実装(javascript)
constapp=newVue({el:'#app',data:{mailList:[{email:'sample_a@gmail.com',name:'Alice',dispFlg:true},{email:'sample_b@gmail.com',name:'Bake',dispFlg:true},{email:'sample_c@gmail.com',name:'Cassandra',dispFlg:true},{email:'sample_d@gmail.com',name:'Dick',dispFlg:true},{email:'sample_e@gmail.com',name:'Ellie',dispFlg:true}]},methods:{onClick(index){if(this.mailList[index].dispFlg){constresult=confirm(this.mailList[index].name+"のメールアドレスを無効にしますか?");if(!result){this.mailList[index].dispFlg=true;}}}}})
イケてないところ
キャンセルだった場合に、this.mailList[index].dispFlg = true;
とすることでチェックボックスをONに戻そうとした。
しかし、これは公式ドキュメントにも書かれている通り、
配列に対してインデックスと一緒にアイテムを直接セットしてもVueは変更を検知できません。
結果、画面にはチェックボックスがOFFの状態で表示されてしまいます。
対処方法1:preventDefaultを使う
preventDefaultはイベントの伝搬を止めます。
実装(html)
<trv-for="(item, index) in mailList":key="item.email"><td>{{item.email}}</td><td>{{item.name}}</td><td><inputtype="checkbox"name="checkbox"v-model="item.dispFlg"@click="e => onClick(e,index)"></td></tr>
indexと一緒にEventオブジェクトもパラメータで渡します。
実装(javascript)
methods:{onClick(e,index){if(this.mailList[index].dispFlg){constresult=confirm(this.mailList[index].name+"のメールアドレスを無効にしますか?");if(!result){e.preventDefault();}}}}
preventDefault()
でイベントの伝搬を止めることで、チェックボックスのON⇔OFFが切り替わらなくなります。
ただ、当時は実装上の都合により preventDefault()
を使えなかったので頭を悩ますことになりました・・・(子コンポーネントから親コンポーネントにEventを渡せなかった)
対処方法2:key属性を与えて更新する
keyは更新前後のデータの差分抽出にVue内部で使われている特殊な属性です。
実装(html)
<divid="app"><table><thead><tr><th>メールアドレス</th><th>ユーザ名</th><th>表示</th></tr></thead><tbody:key="updateKey"><trv-for="(item, index) in mailList":key="item.email"><td>{{item.email}}</td><td>{{item.name}}</td><td><inputtype="checkbox"name="checkbox"v-model="item.dispFlg"@click="onClick(index)"></td></tr></tbody></table></div>
tbody
に対してkeyを付与します。
実装(javascript)
constapp=newVue({el:'#app',data:{mailList:[// :// 省略// :],updateKey:true},methods:{onClick(index){if(this.mailList[index].dispFlg){constresult=confirm(this.mailList[index].name+"のメールアドレスを無効にしますか?");if(!result){this.updateKey=!this.updateKey;}}}}
新たに updateKey
というデータを用意。
キャンセルの場合、 updateKey
の値を更新することでVueに <tbody>
配下の再描画を促します。
結果、チェックボックスはOFFのままとなります。
まとめ
ユーザの操作に対してVueインスタンスで保持しているデータを更新させたくない場合、preventDefault
または key
を試してみよう。