最近の学び
仕事で久々にrailsでview周りを触ったので、そのことについて書いておく。
selectでdata-id
ユーザーへの情報の一覧を表示する管理者向けの画面に、その情報がユーザーへ公開されているか否かを表示する項目があった。
これまでは別途情報ごとの編集画面に行きそのフラグを更新していたが、管理者側の要望で情報の一覧画面からそのフラグ更新をしたいと要望があったので、その改修を行った。
はじめは
<% @information.each do |info| %> 中略 <select name="published[#{info.id}]"> <%= options_for_select({ '公開': true, '非公開': false }) %> </select>
というふうに書いていたんだけど、レビュー時にname
属性にidを入れるよりもdata-*
属性にidを入れるほうが適切と言われた。
MDNの説明的にも確かにそうだなあと思い以下のように変更:
<select name="published" data-id="#{info.id}"> <%= options_for_select({ '公開': true, '非公開': false }) %> </select>
ajaxでの送信の際、name
にidを混ぜているとslice
などを使った文字列操作が入りめんどくさかったが data-*
属性を使うとidの取得が簡単になるので便利。
ただ、ひとつ注意すべきなのは、railsのselect
ヘルパー(formの内部で使うやつではないほう)ではdata-*
属性が使えなかった(下のようなやり方はできなかった)。
select
ヘルパーとform.select
ヘルパーで違うのか、railsのバージョンが新しいからなのかはよくわからない。
bubbling phaseでイベント取得
上のセレクトボックスの話に関してもうひとつ続ける。
上のような、行う処理は同じで渡すパラメータだけ違うインターフェースがたくさんある場合、イベントハンドラをどう書くかで困った。
onchange
属性を各インターフェースにつければいいって話なんだけど、erb
ファイルとは別のファイルに書いたイベントハンドラを読み込むと、イベントハンドラがうまく発火しない。
onchange
属性に書かれたものは、erb
ファイル内に書いたイベントハンドラであればうまく動くのだが、webpacker
を導入していた && npm
でインストールしたライブラリを使いたいこともあり、やはりerb
ファイルとは別のファイルにイベントハンドラを書きたかった。
はじめはイベントハンドラを書いたファイルの中で
const selectElms = document.getElementsByName('published') Array.from(selectElms).forEach((elm) => { elm.addEventListener('change', (e) => someEventHandler(e)) })
としていたのだが、forEach
が入るのがめんどくさい。
そこで、
const selectParent = document.getElementById('selectParent') selectParent.addEventListener('change', (e) => someEventHandler(e))
というように、bubbling phaseで処理するようにすることでforEach
で回す必要がなくなりコード的にすっきりさせることができた。
これまでは、イベントの伝播はすぐ止めるようにしてたので伝播することのありがたみってよくわからなかったが、今回はじめてそのありがたみが少しわかった気がする。