🦞

HTML の data-xxxx はとっても便利

2023/11/06に公開

ラブグラフでエンジニアをしております横江 ( @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-withdata-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