可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This is the code I currently have:
<%= 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"} %>
All it does is to display in one dropdown all the categories and in another all the subcategories.
like this
Question: How to make just the specific subcategories appear depending on the chosen main category. With the code above, it shows all the categories and all subcategories.
Everything is linked in the model, the has_many, and belongs_to...and category_id and subcategory_id..everything is working properly, I just don't know how to show the specific subcategories within chosen category.
My attempt:
<% if (Category.where(:name=>"Intro")) do |d| %>
<% d.subcategories.each do |subcategory| %>
<%= link_to subcategory.name, gigs_path(subcategory: subcategory.name) %>
<% end %>
<% end %>
This code gives an error. I though to say if, for example, the user picks the category called "Intro" than list all the "Intro subcategories". But it didn't work out - my code is obviously wrong.
Thank you.
回答1:
I assume you want this to happen without reloading the page? You won't get around a bit of JavaScript then. Here's the general workflow:
- when the category dropdown is changed, send an Ajax request which will respond with JavaScript and insert the correct values into the Subcategory dropdown.
For the sake of this example I will just assume that your form (the model that belongs to a category) is a post. You didn't seem to mention the model.
Let's try this:
views/posts/_form:
I will wrap the subcategories selct box in a subcategories_select
div, which enables us to replace the whole content later.
<%= 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>
assets/javascripts/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
});
});
config/routes.rb
# we need a custom route for our get_subcategories action
resources :categories do
member do
get :get_subcategories, defaults: { format: "js" }
end
end
controllers/posts_controller.rb
Important: I assume that a category has_many subcategories and subcategories have a category_id, which meansbelong_to a category. If that's not the following won't make sense.
# our custom controller action
def get_subcategories
@subcategories = Subcategory.where(category_id: params[:category_id])
end
app/views/posts/get_subcategories.js.erb
Here we will replace the content of our subcategories_select div and insert a collection_select with the appropriate options.
$('#subcategories_select').html("<%= j collection_select(:post, :category_id, @subcategories, :id, :title), { prompt: 'Select subcategory...' }, { disabled: false } %>");
Please note that I did this from the top of my head, so there might be errors, but this is one approach to dynamically populate select boxes, or in general change anything on a page without reloading.
回答2:
This is what solved my question
in javascript folder (masonry gem must be installed)
$ ->
$('#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!")
in Gig controller
respond_to :html, :js, :json
def update_sub_categories
@cats = Subcategory.where(category_id: params[:category_id]).all
respond_with(@cats)
end
Than i created a partial in gig view
_subcategory.html.erb
and put this code
<option value="<%= cat.id %>"><%= cat.name %></option>
than another partial in gig view called _update.html.erb
put this code
$("#gig_subcategory_id").empty().append("<%= escape_javascript(render(:partial => "subcategory", :collection => @cats, :as => :cat)) %>")
Finally in the view to display the category and subcategory,i used
<%= 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"} %>
回答3:
Filtering a collection_select with js may be very difficult. I recommend using group_collection_select which filters the data if the relations are correct. Asumming you have a data model that looks something like the one mentioned in the above answer, the view should have something like this:
views/posts/_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' } %>
Right now you will be able to see both select forms but the grouped_collection_select box shows kind of nested options. in order to show only the necesary subcategories we will need to do some changes in the javascript, in my case y use coffee and my files will be named .coffee instead of .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()
I owe my answer to this source where you can find more details about using group_collection_select
回答4:
So the embedded ruby that you wrote gets evaluated before being sent to the 'client side'. What that means is that the code you wrote gets turned into static HTML and sent to the user.
What you want is to use something that can provide logical operations on the user's browser. That means javascript.
Checkout: AngularJS: https://angularjs.org/