HTML の data-xxxx はとっても便利
ラブグラフでエンジニアをしております横江 ( @yokoe24 ) です。
Rails と Vue.js の連携での悩み
Vue.js は薄く使えることが強みですが、
それゆえに時折困ることがあります。
よくある Rails のフォームとしてこのようなものがあります。
<%= form_with model: @address do |f| %>
<%= f.label :city %>
<%= f.text_field :city, required: true, autocomplete: "address-level2" %>
<% end %>
これを、例えば「郵便番号が入力されたら市区町村などが自動入力されるようにしたい!」などの都合で Vue.js に対応させると、
テンプレートファイルはこのようになります。
<div id="app">
<%= form_with model: @address do |f| %>
<%= f.label :city %>
<%= f.text_field :city, "v-model": "cityName", required: true, autocomplete: "address-level2" %>
<% end %>
</div>
JavaScript 側は、最小限のところだけ書くとこのようになっているでしょう。
new Vue({
el: 'app',
data: {
cityName: '',
},
});
Vue.js から cityName
でのデータバインディングが出来て扱いやすくなりました。
しかし、ひとつ困るのが、一度データが保存されたあとの編集時です。
元のコードでは Rails がいい感じに、
現在のデータをテキストフィールドの初期値として入れてくれていました。
しかし、 Vue.js を使ったパターンでは、
cityName
が初期では空文字なので、
テキストフィールドは空の状態として上書きされてしまいます。
HTML属性のどれに初期値を入れるか迷った
そうなると、じゃあ初期値を HTML のどこかに持たせて JavaScript 側で拾ってくるとよさそう……
と思ったものの、どう持たせるといいか迷いました。
いちおう Rails には gon という
HTMLとJSをつなぐ黒魔術的なライブラリがあるものの、
ライブラリの力を使うのは極力避けたいところです。
そう思いながら HTML属性(HTML attributes)の一覧 を見ていたところ、
見つけました!! data-* を!
Rails では data-disable-with
や data-confirm
などでお世話になっている要素ですね。
(参考: https://railsguides.jp/v6.0/working_with_javascript_in_rails.html#組み込みヘルパー )
data-xxx
について Mozilla のドキュメントを読むと、
data-* グローバル属性 はカスタムデータ属性と呼ばれる属性の組を作り、HTML と、スクリプトによる DOM 表現との間で、固有の情報を交換できるようにします。
( https://developer.mozilla.org/ja/docs/Web/HTML/Global_attributes/data-* )
と書かれており、 まさに今回のような使い道にピッタリです!
data-* すごい。camelCase にしてくれる
実際に使ってみました!
- <%= f.label :city %>
- <%= f.text_field :city, "v-model": "cityName", required: true, autocomplete: "address-level2" %>
+ <%= f.label :city, for: "cityNameInputField" %>
+ <%= f.text_field :city, "v-model": "cityName", id: "cityNameInputField", "data-initial-value": f.object.city, required: true, autocomplete: "address-level2" %>
このように data-initial-value
キーを追加し、
JavaScript ファイル側には以下のように書きました。
new Vue({
el: 'app',
data: {
cityName: '',
},
created() {
const element = document.querySelector('#cityNameInputField');
this.cityName = element.dataset.initialValue;
},
});
すごいのは、HTML側で data-initial-value
とケバブケースで書いたものを、
JavaScript では initialValue
として、ちゃんとキャメルケースで取り出せることですね!
逆に、 initialValue
で全ファイルを検索してもどこで値を定義しているのかわからない問題も起こりうるので、
JavaScript のコード内で dataset
と書いている箇所があったら、そのことには注意ですね。
これで無事に問題は解消しました!
HTML から JavaScript に楽に値を渡せる便利な data-xxx
、これからも存在を忘れないでいたいと思います!
Discussion