2015-04-23 108 views
3

这只是子类是我目前拥有的代码:显示所选类别

<%= f.collection_select :category_id, Category.all, :id, :name, {prompt: "Choose a category"} %> 
<%= f.collection_select :subcategory_id, Subcategory.all, :id, :name, {prompt: "Choose a subcategory"} %> 

它所做的就是在一个下拉所有的类别来显示,而在另一个所有的子类别。 这样the drop downs.

问题:如何使刚刚特定的子类别取决于所选择的主要类别出现。使用上面的代码,它会显示所有类别和所有子类别。

一切都在模型中,的has_many和belongs_to的...和CATEGORY_ID和subcategory_id..everything工作正常联系,我只是不知道如何表达所选类别中的具体子类。

我尝试:

<% if (Category.where(:name=>"Intro")) do |d| %> 
    <% d.subcategories.each do |subcategory| %> 
     <%= link_to subcategory.name, gigs_path(subcategory: subcategory.name) %> 
    <% end %> 
    <% end %> 

该代码给出了一个错误。我想说的是,例如,如果用户选择名为“Intro”的类别而不是列出所有“Intro子类别”。但它没有解决 - 我的代码显然是错误的。

谢谢。

回答

0

所以你写的嵌入式ruby在被发送到'客户端'之前会被评估。这意味着您编写的代码会变成静态HTML并发送给用户。

你想要的是使用可以在用户的​​浏览器上提供逻辑操作的东西。这意味着JavaScript。

结帐:AngularJS:https://angularjs.org/

+4

@MikeMcCallen前端积极与后端通信的更多细节。所以来自'前端'的函数在'后端'调用函数,然后它接收结果并处理它们。我建议你阅读更多关于ajax,并考虑网络的工作原理;) –

+0

我一定误解了你的问题。在我看来,当用户在第一个选项('选择类别')中选择一个选项时,您试图更改第二个下拉菜单('选择一个子类别')的内容。看起来你试图在服务器端实现这一点,在某些圈子里,这被认为是错误的。 每当用户更改第一个菜单中的选项,然后使用该响应来填充第二个菜单中的选项时,您可能会尝试的是对您的控制器执行AJAX调用。但是,这又有点不正统。 –

+0

这绝对可以在rails中实现。使用简单的json API。除非我误解你的回答。 –

7

我假设你想这无需重新加载页面发生的呢?那么你不会绕过一些JavaScript。这里的一般工作流程:

  • 当类别下拉列表改变时,发送一个Ajax请求将与JavaScript的响应,并插入正确的值到子类别下拉菜单。

为了这个例子我只是假设你的表单(属于一个类别的模型)是一个帖子。你似乎没有提到这个模型。

让我们试试这个:

的意见/职位/ _form
我将包裹的子类别SELCT箱在subcategories_select DIV,这使我们后来更换整个内容。

<%= f.collection_select :category_id, Category.all, :id, :name, { prompt: "Choose a category" }, id: "category_id" %> 

<div id="subcategories_select"> 
<%= f.collection_select :subcategory_id, Subcategory.all, :id, :name, { prompt: "Choose a subcategory" }, { disabled: true } %> 
</div> 

资产/ Java脚本/ posts.js.erb

# select the element to watch for changes 
$('form').on('change', '#category_id'), function() { 
    var category_id = $(this).val(); # save the category_id set in the first dropdown 

    $.ajax({ 
    url: "/categories/" + category_id + "/get_subcategories", # a custom route, see routes.rb further down 
    type: "GET", 
    dataType: "script", # we expect a response in js format 
    data: { "category_id": category_id } # the only value we will need to get the subcategories 
    }); 
}); 

配置/路线。RB

# we need a custom route for our get_subcategories action 
resources :categories do 
    member do 
    get :get_subcategories, defaults: { format: "js" } 
    end 
end 

控制器/ posts_controller.rb
重要:我认为一个类别的has_many子类别和子类别具有CATEGORY_ID,其meansbelong_to一个类别。如果这不是以下将是没有意义的。

# our custom controller action 
def get_subcategories 
    @subcategories = Subcategory.where(category_id: params[:category_id]) 
end 

应用程序/视图/职位/ get_subcategories.js.erb
在这里,我们将取代我们subcategories_select div的内容并插入一个collection_select用适当的选项。

$('#subcategories_select').html("<%= j collection_select(:post, :category_id, @subcategories, :id, :title), { prompt: 'Select subcategory...' }, { disabled: false } %>"); 

请注意,我这样做是从我的头顶,所以有可能是错误的,但这是动态填充选择框,或在页面上一般改变什么而无需重新加载一个方法。

+0

你确定它必须是** assets/javascripts/posts.js.erb **我的意思是结尾.js.erb吗?我完成了你所说的,而且类别是可点击的,并显示所有类别,因为它应该和子类别无论我做什么,都不可点击。请给我你的bitbucket用户名,我将发送邀请,回我的回购。谢谢。 –

+2

只要包含在资产管道中,就可以将JavaScript部分放在任何位置。为了这个例子,暂时将它放在application.js中,看看它是否有效。正如我所说的,我想概述一种解决这个问题的方法。虽然我在很多应用程序中使用了这种方法,但我没有测试这个特定的示例。您可能需要注意浏览器中的服务器日志和JS控制台,以发现任何错误。是的,结局是好的 - js.erb使您能够在您的javascript响应中使用ruby,类似于html.erb – thirdsun

+1

@MikeMcCallen - 请接受此答案,它提供了复制粘贴级别的支持。 –

1

这是解决我的问题

的JavaScript文件夹中(必须安装砖石宝石)

$ -> 
    $('#gigs').imagesLoaded -> 
    $('#gigs').masonry 
     itemSelector: '.box' 
     isFitWidth: true 

    $(document).on 'change', '#gig_category_id', (evt) -> 
    $.ajax 'update_sub_categories', 
     type: 'GET' 
     dataType: 'script' 
     data: { 
     category_id: $("#gig_category_id option:selected").val() 
     } 
     error: (jqXHR, textStatus, errorThrown) -> 
     console.log("AJAX Error: #{textStatus}") 
     success: (data, textStatus, jqXHR) -> 
     console.log("Dynamic country select OK!") 
在千兆控制器

respond_to :html, :js, :json 
    def update_sub_categories 
    @cats = Subcategory.where(category_id: params[:category_id]).all 
    respond_with(@cats) 
    end 

比我创造了演出视图 部分_subcategory.html.erb 并将此代码

<option value="<%= cat.id %>"><%= cat.name %></option> 

比演出视图另一局部称为_update.html.erb 把这个代码

$("#gig_subcategory_id").empty().append("<%= escape_javascript(render(:partial => "subcategory", :collection => @cats, :as => :cat)) %>") 

最后,在视图中显示的类别和子类别,我使用

<%= f.collection_select :category_id, Category.all, :id, :name, {prompt: "Choose a category"} %> 
    <%= f.collection_select :subcategory_id, Subcategory.all, :id, :name, {prompt: "Choose a subcategory"} %> 
1

过滤一个collection_select与js可能是非常困难的。如果关系正确,我建议使用group_collection_select过滤数据。 Asumming你有一个看起来像在上面的回答中提到的一个数据模型,视图应该是这样的:

的意见/职位/ _form:

<%= f.collection_select(:category_id, Category.all, :id, :name,  
       { prompt: 'Select a category' }, { id: 'category-select' }) %> 

<%= f.grouped_collection_select :subcategory_id, Category.all, :subcategories, 
      :name, :id, :name, { include_blank: 'Select a sub category' }, 
               { id: 'subcategory-select' } %> 

现在你就可以看到两个选择窗体,但grouped_collection_select框显示了嵌套选项的种类。为了只显示需要的子类,我们需要在javascript中进行一些更改,在我的情况下使用咖啡,我的文件将被命名为.coffee而不是.js.erb

app/assets/javascripts/posts .coffee:

jQuery -> 
    subcat = $('#subcategory-select').html() 
    $('#category-select').change -> 
    cat = jQuery('#category-select').children('option').filter(':selected').text() 
    options = $(subcat).filter("optgroup[label='#{cat}']").html() 
    if options 
     $('#subcategory-select').html(options) 
    else 
     $('#subcategory-select').empty() 

我欠我回答这个source在这里你可以找到有关通过Ajax调用使用group_collection_select

+0

真棒,比围绕AJAX摆弄容易得多,对我来说非常适合。 – mohnstrudel