Отрисовка полей на основе рельсов выбора категории - PullRequest
0 голосов
/ 18 июня 2020

Итак, у меня есть следующая форма, использующая кокон, вмещающий некоторые поля в частичном

<%= form_with(model: tournament, local: true, class: "mt-8 md:mt-12") do |f| %>
  <% if tournament.errors.any? %>
    <div id="error_explanation" class="bg-red-100 text-red-700 rounded-md shadow-sm p-8">
      <h2 class="font-bold text-base"><%= pluralize(tournament.errors.count, "error") %> prohibited this tournament from being saved:</h2>

      <ul>
        <% tournament.errors.full_messages.each do |message| %>
          <li class="mt-1 font-semibold text-sm"><%= message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  ....

  <div class="text-xl font-black mt-8">
    Tournament Standings
    <div class="border-2 border-indigo-600 bg-indigo-600 w-1/6 md:w-10 mt-1"></div>
  </div>

  <%= f.fields_for :tournament_standings do |tournament_standing| %>
    <%= render 'tournament_standing_fields', f: tournament_standing %>
  <% end %>

  <div class="mt-4 border-t border-gray-200 pt-5">
    <span class="mt-4 inline-flex rounded-md shadow-sm">
      <%= f.submit class: "mr-4 inline-flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out" %>
      <%= link_to_add_association 'Add tournament standings', f, :tournament_standings, class: "inline-flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out mr-2" %>
    </span>
  </div>
<% end %>

Внутри этого рендера у меня есть следующие

<div class="mt-4">
  <%= f.label "Select tournament game", class: "block text-sm font-medium text-gray-700" %>
  <div class="mt-1 rounded-md shadow-sm">
    <%= f.select(:category_id, Category.all.map{|c| [c.name, c.id]}, {prompt: true}, { class: "ts_select block form-select w-full transition duration-150 ease-in-out sm:text-sm sm" }) %>
  </div>
</div>

<div class="nested-fields">
  <div class="mt-4">
    <%= f.label :team, class: "block text-sm font-medium text-gray-700" %>
    <div class="mt-1 rounded-md shadow-sm">
      <%= f.select(:team_id, Team.all.map{|t| [t.name, t.id]}, {prompt: "Select a team"}, { class: "block form-select w-full transition duration-150 ease-in-out sm:text-sm" }) %>
    </div>
  </div>

  <div class="flex flex-col md:flex-row">
    <div class="mt-4 md:mr-4">
      <div class="mt-1">
        <div class="flex rounded-md shadow-sm">
          <span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
            Position
          </span>
          <%= f.number_field :position, class: "flex-1 form-input block w-full rounded-none rounded-r-md transition duration-150 ease-in-out sm:text-sm sm" %>
        </div>
      </div>
    </div>

    <%= render partial: "tournaments/fpartials/default", tournament: @tournament, locals: { f: f } %>
    <%= render partial: "tournaments/fpartials/rocket_league_fields", tournament: @tournament, locals: { f: f } %>

    <div class="mt-4 md:mr-4">
      <div class="mt-1">
        <div class="flex rounded-md shadow-sm">
          <span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
            Assists
          </span>
          <%= f.number_field :assists, class: "flex-1 form-input block w-full rounded-none rounded-r-md transition duration-150 ease-in-out sm:text-sm sm" %>
        </div>
      </div>
    </div>

    <div class="mt-4">
      <div class="mt-1">
        <div class="flex rounded-md shadow-sm">
          <span class="inline-flex items-center px-3 rounded-l-md border border-r-0 border-gray-300 bg-gray-50 text-gray-500 sm:text-sm">
            Prize $
          </span>
          <%= f.number_field :prize, class: "flex-1 form-input block w-full rounded-none rounded-r-md transition duration-150 ease-in-out sm:text-sm sm" %>
        </div>
      </div>
    </div>
  </div>

  <%= link_to_remove_association 'Delete tournament standing', f, class: "mt-4 inline-flex justify-center text-sm font-medium" %>
</div>

Которые работают, как вы можете видеть: есть две части рендеринга, которые я хочу иметь возможность отображать эти поля на основе выбранной категории category_id по умолчанию должны быть отображаемые поля по умолчанию, а поля ракетной лиги скрыты, однако, допустим, пользователь выбирает категорию rocket league, затем поля по умолчанию должны быть скрыты, а поля ракетной лиги будут отображаться.

1 Ответ

1 голос
/ 19 июня 2020

Есть два способа сделать это:

  1. Визуализировать все частичные данные при загрузке страницы и использовать Javascript, чтобы показать / скрыть соответствующий фрагмент при изменении поля выбора.
  2. Используйте запрос AJAX для рендеринга правильного партиала, а затем Javascript, чтобы динамически перетащить его на страницу / DOM.

Если у вас есть тонна возможных партиалов или они действительно большие, вариант 2 предпочтительнее. Но если вы говорите только о переключении между двумя вещами, вариант 1 более прост.

Для варианта 1:

  1. Оберните ваши частичные данные в <div> с отдельными идентификаторами, чтобы ваш Javascript мог получить к ним доступ. В приведенном выше коде вы, похоже, изначально не устанавливаете значение в поле выбора, поэтому, вероятно, вы начнете с набора «по умолчанию», показывающего:

    <div id="default-fields">
      <%= render partial: "tournaments/fpartials/default", tournament: @tournament, locals: { f: f } %>
    </div>
    <div id="rocket-fields" hidden>
      <%= render partial: "tournaments/fpartials/rocket_league_fields", tournament: @tournament, locals: { f: f } %>
    </div>
    

    (вы также можете, конечно, установить 'hidden' также условно во время рендеринга.)

  2. Добавить обработчик Javascript, который срабатывает при изменении выбранного значения. «Ненавязчивый» способ сделать это - добавить прослушиватель событий Javascript в пакет Javascript вашей страницы (обычно в app/assets/javascript). Что-то вроде:

    document.addEventListener('turbolinks:load', () => {
      const element = document.getElementById('tournament[category_id]');
      if (element) {
        $('#tournament[category_id]').change((e) => {
          if (e.target.value == 'whatever_rocket_id_is') {
            ('#default-fields').hide();
            ('#rocket-fields').show();
          }
          else {
            ('#default-fields').show();
            ('#rocket-fields').hide();
          }
        });
      }
    });
    

Одно примечание: поскольку вы хотите иметь тесную связь между категорией и показанными полями, вам не следует использовать идентификатор записи в качестве ключа в выбрать варианты; он может измениться, и вы не хотите жестко кодировать идентификаторы записей в своем Javascript. Лучше всего, вероятно, использовать имя категории как для ключа, так и для значения. Вероятно, стоит также в первую очередь пересмотреть эту тесную связь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...