RJS: Используя поле наблюдения на select_tag - PullRequest
2 голосов
/ 23 февраля 2009

Раскрывающееся меню (созданное меткой select_tag) в моем приложении должно вызывать действие filter-category-action, как только пользователь изменяет значение в выпадающем меню И нажимает кнопку «Перейти».

Теперь я хотел бы избавиться от кнопки «Перейти» и заставить наблюдателя (наблюдаемое поле?) Вызывать действие filter-category-action, как только пользователь изменит значение в выпадающем меню.

Ниже вы видите код, который я написал. Он работает с помощью кнопки «Перейти», но не работает, просто меняя значение в выпадающем меню. Что не так с моим помощником наблюдать_категории?

Частичное представление с выпадающим меню и списком проектов

    <!-- drop down menu -->
    <% form_tag(filter_category_path(:id), :method => :post, :class => 'categories') do %>
       <label>Categories</label>
       <%= select_tag(:category, options_for_select(Category.all.map {|category| [category.name, category.id]}, @category_id)) %>
       <!-- i would like to get rid of this button -->
       <%= submit_tag "Go" %>
     <% end %>

   <!-- list of projects related to categories chosen in drop down menu -->
   <ul class="projects">
     <% @projects.each do |_project| %>
       <li>
         <%= link_to(_project.name, _project) %>
       </li>
     <% end %>
   </ul>

   <%= observe_category_select -%>

HelperMethod

  def observe_category_select
    observe_field(
                  :category,
                  :url        =>  filter_category_path(:id),
                  :with       =>  'category',
                  :on         =>  'change'
    )
  end

Вывод Javascript HelperMethod

<script type="text/javascript">
//<![CDATA[
   new Form.Element.EventObserver('category', function(element, value) {
     new Ajax.Request('/categories/id/filter', {asynchronous:true, evalScripts:true, parameters:'category=' + encodeURIComponent(value) + '&authenticity_token=' + encodeURIComponent('edc8b20b701f72285068290779f7ed17cfc1cf8c')})
   }, 'change')
//]]>
</script>

Категории контроллера

class CategoriesController < ApplicationController
  def show
    @category = Category.find(params[:id])
    @category_id = @category.id
    @projects = @category.projects.find(:all)

    respond_to do |format|
      format.html # index.html.erb
    end
  end

  def index
    @projects = Category.find(params[:id]).projects.find(:all)

    respond_to do |format|
      format.html # index.html.erb
    end
  end

  def filter
    @category = Category.find(params[:category])
    @category_id = @category.id
    @projects = @category.projects.find(:all)

    respond_to do |format|
      format.html # index.html.erb
    end    
  end

конец

Вывод 'рейковых маршрутов | grep filter '

             filter_category POST   /categories/:id/filter                   {:controller=>"categories", :action=>"filter"}
   formatted_filter_category POST   /categories/:id/filter.:format           {:controller=>"categories", :action=>"filter"}

Ответы [ 5 ]

6 голосов
/ 23 февраля 2009

Ваше действие контроллера фильтра должно отвечать на Javascript, а не просто на обычный HTTP-запрос.

def filter
  @category = Category.find(params[:category])
  @category_id = @category.id
  @projects = @category.projects.find(:all)

  respond_to do |format|
    format.js # filter.rjs
  end    
end

Или, если вы хотите, чтобы это действие отвечало в любом контексте, поместите оба в блок:

respond_to do |format|
  format.html # filter.html.erb
  format.js # filter.rjs
end    

Для этого требуется, чтобы у вас был файл вида filter.rjs, который будет выглядеть примерно так:

page.replace_html :id_of_element_to_replace_html, :partial => "name_of_partial"
1 голос
/ 11 марта 2009
  def observe_category_select
    observe_field(
                  :category,
                  :url        =>  filter_category_path(:id),
                  :with       =>  :category_id,
                  :on         =>  :onchange,
                  :update     =>  :projects
    )
  end

: onchange - это гоча - у меня ушло много времени, чтобы разобраться с этим. РЕДАКТИРОВАТЬ: Похоже, вы решили это.

Если вы хотите сбросить раскрывающийся список и состояние отображения проекта, включите функцию, подобную этой, в отображаемую часть:

<%= link_to_function "close category", :title => 'close category' do |page| 
        page.select("#category").each do |element|
            element.value = "Choose Category"
            page << "window.fireEvent($(\"category\"), 'change');"
        end
        page.replace_html :projects, "<li></li>" 
    end-%>

Это установит список выбора в значение по умолчанию, удалит все элементы списка, относящиеся к последней отображаемой категории, и подготовит ul для отображения новых li по умолчанию. Должен быть вызван fireEvent, иначе наблюдатель не будет работать, если вы выберете ту же категорию, которая была только что скрыта.

Поскольку наблюдатель уволен, действие контроллера должно с ним справиться:

 def filter
  begin        
    @category = Category.find(params[:category])
    @category_id = @category.id
    @projects = @category.projects.find(:all)
  rescue
    @category = "choose"
  end
  render :layout => false
 end

Если категория не найдена, установите @category в строку и проверьте в частичном представлении

<% if @category.eql?('choose') %>
  <li>choose category</li>
<% else %>
 # loop through projects returning them wrapped in li tags
<% end %>

Не красиво, но работает.

1 голос
/ 23 февраля 2009

Моей первой мыслью было, что это могут быть некоторые проблемы с областями видимости. Я предполагаю, что filter_category_path является одним из ваших помощников пути маршрута - идентификатор или значение категории (in: with) могут не входить в область действия вспомогательного метода.

Когда вы просматриваете страницу, можете ли вы увидеть JavaScript, который выводится при вызове наблюдаемое поле ?

Используя Firebug, вы видите какие-либо запросы Ajax?

Что-нибудь появляется в вашем файле development.log?

0 голосов
/ 07 января 2010

FWIW - я все еще довольно новичок в рельсах, и я наткнулся на тот факт, что новое настраиваемое действие должно быть определено в вашем файле rout.rb (вроде бы задним числом, но мне никогда не приходилось делать это раньше) .

Если вы используете отдыхающие маршруты, просто прикрепите a: collection => {: filter =>: get} к концу строки маршрута вашего ресурса (например, map.resource: Categories,: collection => {: filter =>: получить}).

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 23 февраля 2009

У меня была такая же проблема в моем реальном проекте. Я решил это с помощью атрибута onchange в теге select:

<%= select_tag @procuct, 
        options_for_select(
            @product.properties.map {|property| [property.name, property.id]}),
        :onchange => "HERE_A_CALL_TO_YOUR_JS_FUNCTION();" %>

ОБНОВЛЕНИЕ: Я помещаю Ajax Call в JS-функцию, вместо этого вы можете поместить все в оператор onchange, я думаю, вы также можете поместить туда "родные Rails" методы JS.

...