問題:select2のchangeイベントが呼ばれない
stimulusを使っているアプリケーション内でselect2を導入しようとした時の話です。
以下のように、都道府県のselect2の値が変更された時に市区町村を取得してくるような処理を書いていたのですが、なぜかfetchCitiesが呼ばれない。
hoge.html.slim
= f.select :prefecture_id,
Prefecture.all.map { |p| [p.name, p.id] },
{ required: true },
data: { 'hoge-target': 'prefectureSelectBox', action: "change->hoge#fetchCities" }
hoge_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ['prefectureSelectBox']
connect () {
$(this.prefectureSelectBoxTarget).select2
}
fetchCities (e) {
// 市区町村を取得する処理
}
}
解決策:select2の変更時にchangeイベントを発火させる
そこで参考にしたのが以下の記事。
select2はネイティブイベントではなく独自のイベントを発火させているため、select2の独自イベントをキャプチャしてネイティブイベントを発火させるようにすれば良いとのことでした。なるほど。
問題は、Select2が'ネイティブ'イベントを使わないことだ。独自のイベントフレームワークを持っているのです。そのため、Select2イベントをキャプチャして、ネイティブイベントを再送信する必要があります。それがわかれば簡単だ!
上記を踏まえて修正したコードが以下になります。
select2変更時にネイティブのchangeイベントも発火されるようになるため、stimulusに設定したアクションが呼ばれfetchCities
が実行されるようになりました。
hoge_controller.js
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ['prefectureSelectBox']
connect () {
$(this.prefectureSelectBoxTarget).select2
// select2の独自イベントをキャプチャしてネイティブchangeイベントを発火
$(this.prefectureSelectBoxTarget).on('select2:select', function () {
const event = new Event('change', { bubbles: true })
this.dispatchEvent(event)
})
}
fetchCities (e) {
// 市区町村を取得する処理
}
}