Динамически генерируемые выбранные меню, не имеющие состояния в режиме редактирования - PullRequest
1 голос
/ 07 октября 2009

Я слежу за Railscast 88, чтобы создать динамически зависимое выпадающее меню. http://railscasts.com/episodes/88-dynamic-select-menus

Я рендеринг этих выпадающих внутри части, которую я использую в многомодельной форме. Форма, которую я использую, следует за процессом Advanced Rails Recipes Райана Бейтса. Поскольку я рендерил раскрывающийся список внутри партиала, мне пришлось отказаться от строгого следования коду Railscast. В приведенной выше ссылке на Railscast комментарии 30-31 и 60-62 касаются этих проблем и предоставляют подход, который я использовал.

Для новых записей все работает отлично. Я выбираю родительский объект из раскрывающегося списка, и JavaScript динамически ограничивает дочерние параметры только теми элементами, которые связаны с выбранным родительским объектом. Я могу сохранить свой выбор, и все отлично работает.

Проблема в том, что когда я возвращаюсь на страницу редактирования и щелкаю раскрывающийся список дочерних элементов, ограничения, связывающие его с родительским объектом, больше не действуют. Теперь я могу выбрать любого ребенка, независимо от того, связан он с родителем или нет. Это основная проблема взаимодействия с пользователем, поскольку список дочерних объектов слишком длинный и сложный. Мне нужно, чтобы дочерние параметры всегда зависели от выбранного родителя.

Вот мой код:

Контроллер # javascripts

def dynamic_varieties
    @varieties = Variety.find(:all)
  respond_to do |format|
    format.js
  end
end

Просмотров # javascripts # dynamic_variety.js.erb

var varieties = new Array();
<% for variety in @varieties -%>
  varieties.push(new Array(<%= variety.product_id %>, '<%=h variety.name %>', <%= variety.id %>));
<% end -%>

function collectionSelected(e) {
  product_id = e.getValue();
  options = e.next(1).options;
  options.length = 1;
  varieties.each(function(variety) {
    if (variety[0] == product_id) {
      options[options.length] = new Option(variety[1], variety[2]);
    }
  }); 
}

Просмотры # пользователи # edit.html.erb

<% javascript 'dynamic_varieties' %>
<%= render :partial => 'form' %>  

Просмотр # users # _form.html.erb

<%= add_season_link "+ Add another product" %>  
<%= render :partial => 'season', :collection => @user.seasons %>  

просмотр # пользователи # _season.html.erb

<div class="season">
<% new_or_existing = season.new_record? ? 'new' : 'existing' %>
<% prefix = "user[#{new_or_existing}_season_attributes][]" %>

<% fields_for prefix, season do |season_form| -%>
  <%= error_messages_for :season, :object => season %>
      <div class="each">
          <p class="drop">
            <label for = "user_product_id">Product:</label> <%= season_form.collection_select :product_id, Product.find(:all), :id, :name, {:prompt => "Select Product"}, {:onchange => "collectionSelected(this);"} %>
            <label for="user_variety_id">Variety:</label>
            <%= season_form.collection_select :variety_id, Variety.find(:all), :id, :name, :prompt => "Select Variety" %>
          </p>

          <p class="removeMarket">
            <%= link_to_function "- Remove Product", "if(confirm('Are you sure you want to delete this product?')) $(this).up('.season').remove()" %>
          </p>            
      </div>
<% end -%>

Ответы [ 2 ]

2 голосов
/ 26 октября 2009

Вот ваш виновник:

<%= season_form.collection_select :variety_id, Variety.find(:all),
  :id, :name, :prompt => "Select Variety" %>

Отлично работает с новой записью, потому что она показывает все, и перезаписывается, когда выбор изменяется в другом окне выбора.

Вам нужно сделать что-то вроде этого:

<% varieties = season.product ? season.product.varieties : Variety.all %>
<%= season_form.select :variety_id, 
  options_from_collection_for_select(varieties, :id, 
  :name, season.variety_id), :prompt => "Select Variety" %>

Который будет использовать только сорта, связанные с season.product. Если season.product не существует, он перечисляет все из них. Он также автоматически выберет правильный вариант, если существующая запись имеет идентификатор_сорта.

Также не мешало бы измениться.

<%= season_form.collection_select :product_id, Product.find(:all), 
  :id, :name, {:prompt => "Select Product"}, 
  {:onchange => "collectionSelected(this);"} %>

до

<%= season_form.select :product_id,  
  options_from_collection_for_select(Product.find(:all),
  :id, :name, season.product), {:prompt => "Select Product"},
  {:onchange => "collectionSelected(this);"} %>

Который выберет правильный продукт при загрузке страницы. Эта вторая часть, по сути, является способом Rails сделать то, что было первым предложением BYK. Однако, учитывая природу метода onchange, заданного для поля выбора, эта строка сама по себе не решит проблему. Это просто улучшит пользовательский опыт, выделив продукт, связанный с сезоном.

1 голос
/ 25 октября 2009

Я думаю, у вас есть два варианта:

  1. Дайте одному из продуктов (или просто первому элементу списка продуктов) атрибут "selected", который заставит браузер всегда выбирать его.
  2. Запустить функцию collectionSelected для dom ready или window.onload, указав в качестве параметра поле выбора списка продуктов.

И примечание: никогда, никогда не доверяйте JavaScript, чтобы заставить пользователя отправлять правильные данные на сервер.

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