RJS:在 select_tag 上使用observe_field
一旦用户更改下拉菜单中的值并点击“执行”按钮,我的应用程序中的下拉菜单(由 select_tag 构建)就应该调用过滤类别操作。
现在我想摆脱“Go”按钮,并让观察者(observe_field?)在用户更改下拉菜单中的值时立即调用过滤器类别操作。
下面你可以看到我写的代码。 它可以使用“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
HelperMethod 的 Javascript 输出
<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
end
“rake 路线”的输出 | grep 过滤器'
filter_category POST /categories/:id/filter {:controller=>"categories", :action=>"filter"}
formatted_filter_category POST /categories/:id/filter.:format {:controller=>"categories", :action=>"filter"}
The dropdown-menu (built by the select_tag) in my application should call the filter-category-action as soon as the user changes the value in the dropdown-menu AND hits the 'Go' button.
Now I'd like to get rid of the 'Go' button and have an observer (observe_field?) call the filter-category-action as soon as the user changes the value in the dropdown-menu.
Below you see the code I've written. It works using the 'Go'-Button but doesn't work by just changing the value in the dropdown-menu. What's wrong with my observe_category_select-helper?
View-partial with dropdown-menu and project list
<!-- 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-Output of the 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>
Categories controller
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
end
Output of '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"}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您的过滤器控制器操作需要响应 Javascript,而不仅仅是响应普通的 HTTP 请求。
或者,如果您希望该操作在任一上下文中响应,请将两者都放入块中:
这需要您有一个视图文件filter.rjs,如下所示:
Your filter controller action needs to respond to Javascript instead of just to a normal HTTP request.
Or, if you want that action to respond in either context, put both in the block:
This requires you to have a view file filter.rjs that will look something like:
我的第一个想法是这可能是一些范围界定问题。 我假设 filter_category_path 是您的路由路径助手之一 - id 或类别值(在 :with 中)可能不在助手方法的范围内。
当您查看页面时,您能看到调用 observe_field 输出的 JavaScript 吗?
使用 Firebug,您能看到发出的任何 Ajax 请求吗?
您的development.log 中是否出现任何内容?
My first thought was it may be some scoping issues. I assume that filter_category_path is one of your route path helpers - the id or the category value (in :with) may not be in scope in the helper method.
When you view the page, can you see the JavaScript that is output by the call to observe_field?
Using Firebug, can you see any Ajax requests being made?
Does anything appear in your development.log?
:onchange 是一个陷阱——我花了很长时间才解决它。 编辑:看起来你已经解决了。
如果要重置下拉列表和项目显示状态,请在渲染的部分中包含这样的函数:
这会将选择列表设置为默认值,并删除与最后显示的类别相关的所有列表项,并为 ul 做好准备新的 li 将在默认情况下显示。 如果您选择刚刚隐藏的相同类别,则必须调用 fireEvent,否则观察者将无法工作。
由于观察者被触发,控制器操作必须处理它:
如果没有找到类别,则将 @category 设置为字符串并在视图部分中进行测试
不漂亮,但它可以工作。
The :onchange is the gotcha - took me a long time to sort it out. EDIT: Looks like you worked that out.
If you want to reset the dropdown and project display state include a function like this in the rendered partial:
That will set the select list to the default value and remove all of the list items related to the last displayed category and get the ul ready for the new li's to be displayed from the default. The fireEvent has to be called or the observer won't work if you select the same category that was just hidden.
Since the observer is being fired the controller action has to deal with it:
If no category is found set @category to a string and test in the view partial
Not pretty but it works.
我在实际项目中也遇到了同样的问题。 我用 select 标签中的 onchange 属性解决了这个问题:
更新:我将 Ajax 调用放在 JS 函数中,而不是你可以将所有内容放在 onchange 语句中,我认为你也可以将“native Rails”JS 方法放在那里。
I had the same problem in my actual project. I solved it with the onchange attribute in the select tag:
UPDATE: I put the Ajax Call in a JS Function, instead you can put everything in the onchange statement, I think you can also put "native Rails" JS methods in there.
FWIW - 我对 Rails 还很陌生,我偶然发现新的自定义操作需要在 paths.rb 文件中定义(事后看来很明显,但我以前从未这样做过)。
如果您使用的是宁静的路线,那么只需添加 :collection =>; {:过滤=> :get} 到资源路由行的末尾(例如,map.resource :categories, :collection => {:filter => :get})。
希望能帮助别人。
FWIW - I'm still pretty new to rails and I stumbled on the fact that the new custom action needs to be defined in your routes.rb file (kinda obvious in hindsight, but I had never had to do this before).
If you're using restful routes, then just tack a :collection => {:filter => :get} to the end of your resource route line (e.g. map.resource :categories, :collection => {:filter => :get}).
Hope that helps somebody out.