0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby on Railsで動的なフォーム要素を扱う方法

Last updated at Posted at 2024-02-27

この記事では、Ruby on Railsで動的にフォームの表示を切り替える一例として、サービス選択に応じて特定のフォームフィールドを表示・非表示する方法を紹介します。主にid属性の動的な生成とJavaScriptを使用したDOMの操作に焦点を当てて解説します。

まず結論

問題の解決策は、id属性をERBテンプレート内で動的に生成し、JavaScriptを用いてそのidを持つ要素の表示を切り替えることでした。具体的には、以下のように記述しました。
※<%= service.id %>の部分が重要でした。
※コメントアウト部分はコンソールでログを出しつつ試行錯誤した履歴です。

app/views/staffs/registrations/edit.html.erb
<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>
app/javascript/controllers/application.js
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コード
});
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?