我的应用程序中的下拉菜单(由select_tag构建)应在用户更改下拉菜单中的值时立即调用filter-category-action并点击“Go”按钮。
现在我想摆脱'Go'按钮并让观察者(observe_field?)在用户更改下拉菜单中的值时立即调用filter-category-action。
下面你看到我写的代码。它使用'Go'按钮工作,但只是更改下拉菜单中的值不起作用。我的observe_category_select-helper出了什么问题?
使用下拉菜单和项目列表查看部分
<!-- 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
端
'rake routes |的输出grep filter'
filter_category POST /categories/:id/filter {:controller=>"categories", :action=>"filter"}
formatted_filter_category POST /categories/:id/filter.:format {:controller=>"categories", :action=>"filter"}
答案 0 :(得分:6)
您的过滤器控制器操作需要响应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.rjspage.replace_html :id_of_element_to_replace_html, :partial => "name_of_partial"
答案 1 :(得分:1)
我首先想到的可能是一些范围问题。我假设filter_category_path是你的路径路径助手之一 - id或类别值(in:with)可能不在helper方法的范围内。
当您查看该页面时,是否可以看到通过调用 observe_field 输出的JavaScript?
使用Firebug,您能看到正在发出的任何Ajax请求吗?
您的development.log中是否有任何内容?
答案 2 :(得分:1)
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 %>
不漂亮,但有效。
答案 3 :(得分:0)
我在实际项目中遇到了同样的问题。我用select标签中的onchange属性解决了它:
<%= select_tag @procuct,
options_for_select(
@product.properties.map {|property| [property.name, property.id]}),
:onchange => "HERE_A_CALL_TO_YOUR_JS_FUNCTION();" %>
更新:我把Ajax调用放在JS函数中,而不是你可以把所有东西都放在onchange语句中,我想你也可以把“native Rails”JS方法放在那里。
答案 4 :(得分:0)
FWIW - 我对rails很陌生,我偶然发现需要在你的routes.rb文件中定义新的自定义动作(后见之明有点明显,但我以前从未这样做过)
如果你正在使用宁静的路线,那么只需添加:collection =&gt; {:filter =&gt; :get}到资源路线的末尾(例如map.resource:categories,:collection =&gt; {:filter =&gt;:get})。
希望能帮助别人。