はじめに
親のカテゴリーを選択すると、子のカテゴリーの中身が選択された親のカテゴリーによって変わるようなセレクトボックスの作り方です。
こちらの記事が動画付きで説明されていてイメージしやすいと思います。
バージョン
- Ruby 3.1.3
- Rails 7.0.4
モデル
モデルはCategory(親要素)とSubCategory(子要素)の2種類で、関連付けされています。
category.rb
class Category < ApplicationRecord
has_many :sub_categories
end
sub_category.rb
class SubCategory < ApplicationRecord
belongs_to :category
end
View
セレクトボックスは使い回しできるようにパーシャル化しています。
_selectbox.html.erb
<%= form_with url: category_search_path, local: true, method: :get do |f| %>
<div class="category-select">
<%= f.collection_select :category, Category.all, :id, :name, include_blank: "カテゴリーを選択してください" %>
</div>
<div id="sub_category">
<%= f.select :sub_category, [], include_blank: "---", class: "default-sub-category-select" %>
</div>
<%= f.submit "検索", class: "btn btn-primary" %>
<% Category.all.each do |category| %>
<template id="sub-category-of-category<%= category.id %>">
<%= f.collection_select :sub_category, category.sub_categories, :id, :name, include_blank: "サブカテゴリーを選択してください" %>
</template>
<% end %>
<% end %>
はじめに全ての子要素のセレクトボックスをtemplateで用意しておき、親要素が選択された時にjavascriptで操作して必要なhtmlを取得するという魂胆です。
Javascript
今回は使い方がわからなかったので勉強のために、jQuery等のフレームワークは使わずに書いています。
category_select.js
// 取得したテキストをhtmlに変換する関数
var stringToHTML = function(str) {
var dom = document.createElement('div');
dom.id = 'sub_category';
dom.innerHTML = str;
return dom;
};
document.addEventListener('turbo:load', function() {
let category = document.querySelector('#category');
let defaultSubCategorySelect = `<select name="sub_category" id="sub_category">
<option value>---</option>
</select>`;
// カテゴリーが変更された時の処理
category.addEventListener('change', function() {
// カテゴリーが選ばれた場合
if (category.value !== '') {
// 空のサブカテゴリーのセレクトボックスを削除
let subCategory = document.querySelector('#sub_category');
subCategory.remove();
// 選択されたカテゴリーに応じたHTMLを挿入
let selectedTemplate = document.querySelector(`#sub-category-of-category${category.value}`);
category.after(stringToHTML(selectedTemplate.innerHTML));
// include_blankの部分が選択された場合
} else {
// サブカテゴリー選択用のセレクトボックスを削除
let subCategory = document.querySelector('#sub_category');
subCategory.remove();
// ダミーのセレクトボックスを挿入
category.after(stringToHTML(defaultSubCategorySelect));
};
});
});
これで動的なセレクトボックスが作成できました。
参考
間違いやご指摘等あればコメントいただけると幸いです。