2015-04-23 111 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