この記事では、Ruby on Railsで動的にフォームの表示を切り替える一例として、サービス選択に応じて特定のフォームフィールドを表示・非表示する方法を紹介します。主にid
属性の動的な生成とJavaScriptを使用したDOMの操作に焦点を当てて解説します。
まず結論
問題の解決策は、id
属性をERBテンプレート内で動的に生成し、JavaScriptを用いてそのid
を持つ要素の表示を切り替えることでした。具体的には、以下のように記述しました。
※<%= service.id %>の部分が重要でした。
※コメントアウト部分はコンソールでログを出しつつ試行錯誤した履歴です。
<div class="service-fields" id="service_fields_<%= service.id %>" style="display: none;">
<%= text_field_tag "staff[service_fees][#{service.id}]", nil, placeholder: "Fee for #{service.name}", id: "staff_service_fees_#{service.id}" %>
<%= text_field_tag "staff[service_durations][#{service.id}]", nil, placeholder: "Duration for #{service.name}", id: "staff_service_durations_#{service.id}" %>
</div>
document.addEventListener('turbo:load', function() {console.log('Page loaded');
console.log(document.querySelectorAll('input[type="checkbox"]'));
document.querySelectorAll('.service-checkbox').forEach(function(checkbox) {
checkbox.addEventListener('change', function() {
// console.log('Checkbox changed');
var serviceId = this.value;
console.log(serviceId);
var serviceFieldsDiv = document.getElementById('service_fields_' + serviceId);
// console.log('service_fields_' + serviceId);
// console.log('Service fields div display before:', serviceFieldsDiv.style.display);
console.log(serviceFieldsDiv)
if (this.checked) {
if (serviceFieldsDiv) serviceFieldsDiv.style.display = 'block'; // service-fieldsが存在する場合に表示
console.log('Service fields div:', serviceFieldsDiv);
// console.log('Service fields div display after:', serviceFieldsDiv.style.display);
} else {
if (serviceFieldsDiv) serviceFieldsDiv.style.display = 'none'; // service-fieldsが存在する場合に非表示
}
});
});
});
試行錯誤の過程
console.logを使ったデバッグ
実装の過程で、特にJavaScriptの挙動を理解するためにconsole.log
を頻繁に使用しました。特に、checkbox.addEventListener('change', function() {...})
内でチェックボックスの状態変更を検知した際の、対応するサービスフィールドの表示・非表示の切り替えを正しく行えるよう、console.log
を用いて変数の状態を確認しながら進めました。
IDの付与方法の変更
初期の実装では、料金や所要時間を入力するinput
タグに直接IDを付与していましたが、複数のフィールドを一括で表示・非表示切り替えるため、外側のdiv
にIDを付与する方法に変更しました。これにより、サービスが選択された際に、関連する全てのフィールドを容易に表示・非表示することが可能になりました。
問題の解析
ブラウザの開発者ツールを使用して、JavaScriptがnull
を返していることに気づきました。これは、指定したIDを持つDOM要素が存在しないために発生するエラーでした。この発見から、HTML要素のIDが正しく設定されておらず、JavaScriptがそれらを見つけられないことが問題の根本原因であることが明らかになりました。
解決策
この問題を解決するために、私はHTMLのID属性の生成方法を見直し、ERBファイル内でid
属性を動的に生成することにしました。これにより、各サービスごとにユニークなIDが割り当てられ、JavaScriptが正確に要素を参照できるようになりました。
<div class="service-fields" id="service_fields_<%= service.id %>" style="display: none;">
また、document.addEventListener('turbo:load', ...)
を使用して、ページの完全な読み込み後にJavaScriptが実行されるようにしました。これにより、動的に生成されたIDを持つ要素がDOMに存在することが保証され、JavaScriptによる表示の切り替えが正常に機能するようになりました。
document.addEventListener('turbo:load', function() {
// 要素の表示切り替えを行うJavaScriptコード
});