Do you need to dynamically change one select menu based on the value of another? Here I show how to filter states/provinces by a selected country using grouped options and a dab of CoffeeScript.
Cool stuff, Ryan. I would change the end of your coffeescript a bit. It is more efficient to use chaining rather than select the #person_state_id element on back to back lines. Plus, I like that it is more concise. Like this:
javascript
if options
$('#person_state_id').html(options).parent().show()
else$('#person_state_id').empty().parent().hide()
One bug to watch out for is selecting a country and state, saving, and then changing it to a country that has no states. The old state will still persist on the object because the state select was emptied, so no value will be POSTed/PUT for state. You can either do .html($("<option>").attr('selected',true)) instead of empty() or you can have a hidden field with the same name, like Rails does for checkboxes.
Slightly OT question. Where did you get this comprehensive list of states/countries? I know many sources but they all require fair amount of work to import in rails db.
Nice screencast Ryan. I have a question though. It seems like this method allows selection of Country only once. Since the State dropdown gets reduced to only the matched states after a Country selection, if you select a new Country that has states, you've now lost the original list of states, so the States dropdown comes up blank. This means if a user makes a mistake selecting their Country, they would need to reload the page in order to undo that mistake. Please correct me if I'm just implementing this wrong.
For the "grouped_collection_select", where is the ":states" parameter created? I use this one (both @sectors and @branches are filled in the controller):
But there is a problem. When try to record the data to db. There are lots of datas in ther e because of numbers of country and state field. For example you write name Bob, choose USA, and state NewYork. Datas are created many times Bob USA NewYork. Why?
When I save the data and want to edit them again, only the first select is shown.
The second select is on "style="display: none" regardless the right values is "option selected="selected".
I used this for an asset management app I'm writing.
Instead of countries/states, I use Makes/Models (which belong to an asset).
Anyway, if you are loading a record that has a make/model saved (or a country/state) then the model (state) will be hidden and you will have to change the make (country) to re-enable it. Then you will have to know it's saved value. So I changed it to only hide the model (state) if there is none saved.
I was able to "fix" the problem when editing an existing product and not having the second select or having it with all the options. It's looking pretty nasty but it works.
Does anyone how what I would do if I have multiple dynamic dropdown in the same form. Say I am allowing someone to pick country state for 3 people at the same time. Is there a way to scope the javascript to look within each person div? Otherwise, the selector would interfere with each other and nothing would work.
I followed this tutorial but am getting JQuery not defined in firebug. I looked at the application.js file and saw that the function was generated correctly. My application layout has javascript_include_tag before anything else is yielded. The funny thing is I have another Jquery function specified for another controller that's working perfectly fine. What am I doing wrong here?
Hello guys,
do you know how to do it with one drop down menu and hidden check boxes? When you click on "Yes" in drop down menu, it will display check boxes underneath but if you click on "never" it will not display anything underneath. Thank you
I could not get this script to work (new to javascript). I am using model User instead of Person. I copied the script as it is on this page and changed all 'person' to 'user'. I put the script is users.js.coffee in my assets/javascript folder. It seems to ignore the script. When I select a state it shows all the countries and related states instead of only displaying the states for the selected country.
I have my fields in a partial that is used both in new and edit.
Again I am new to scripting. I believe that all I have to do is to add the script and it should work. I do this when I want to add functions using Bootstrap. Any help would be appreciated.
I applied this concept to a has_many_through association. When I EDIT a page, the 'Country' is already selected but the 'State' list isn't filtered. I have to click to another 'Country' for the filter of the 'State' list to take effect.
Anyone know how to have the filtering kick-in upon page load?
It appears that this was an issue with console.log, which I now realize wasn't intended to be in the final version of the code. When IE's "F12 Developer Tools" feature was enabled, the dynamic select menus worked as intended. I removed both instances of console.log from the coffeescript file and the issue is gone, with and without F12 Developer Tools enabled. Gotcha on me.
I love Ryan's screencasts. I can't seem to get this working for me, however. The grouped_collection_select works, but my app seems to be ignoring the js.coffee file. I have the include tags in my application.html header, but still, no magic is happening. Does anyone know what I'm doing wrong?
How can I filter the parent data by id and not by text?, I have a model that has 2 records with the same name, and when I select the parent it selects the other one with the same name.
I'm using it with Twitter Bootstrap and Simple_Form. With this in play the parent().hide() function hides the dropdown box, but does not hide the label...
Now I can get round this by created a div around both and hiding that, but that seems to be a bit cumbersome. Looking at the page source I don't see any other obvious divs to use.
With this example, if we select United States or United kingdom it won't work. reason while filter state it is not able filter the value which have space. kindly someone help to get the values
I had the same error. I am using company names instead of countries. All of my companies have a space in the name. Was wondering if you possibly found a fix.
There's a problem with the escaping in firefox 10. Apparently it will escape the escaped_country variable again:
escaped_country === "United\\ States"
true
escaped_country === "United\ States"
false
And it will break the filter...
Any idea what browser we actually need to escape first? I've tested with IE8 and chrome and they also both work with \' in the country name without escaping.
This is a great railscast and I'm hoping to use this with States/Cities.
I'm still a bit new to rails and I don't understand the associations between the states and cities.
Say for instance I select the state of TX. I'd want only Houston, Austin, San Antonio, etc to show up. If I have a State and City model, how would I tie only those cities to the state.
I figured I could do
City.rb
belongs_to :state
State.rb
has_many :cities
And then put a state_id in the City model for the relationship.
But that would be a lot of manual work to get that done. Is there any way around this or a seed file that exists?
You could also use
$('#person_state_id').parent().toggle(options)
Cool stuff, Ryan. I would change the end of your coffeescript a bit. It is more efficient to use chaining rather than select the #person_state_id element on back to back lines. Plus, I like that it is more concise. Like this:
Great video. I tried using this on my site but had no such luck.
I replaced Country and States to States and Cities.
I'm getting the error in my console "cities is not defined" any suggestions?
Thanks, Frank
One bug to watch out for is selecting a country and state, saving, and then changing it to a country that has no states. The old state will still persist on the object because the state select was emptied, so no value will be POSTed/PUT for state. You can either do .html($("<option>").attr('selected',true)) instead of empty() or you can have a hidden field with the same name, like Rails does for checkboxes.
Slightly OT question. Where did you get this comprehensive list of states/countries? I know many sources but they all require fair amount of work to import in rails db.
Thanks Ryan for this awesome railscast....worked like a charm in my webapp. Is it possible to order the states by name?
Try Carmen https://github.com/jim/carmen
Nice screencast Ryan. I have a question though. It seems like this method allows selection of Country only once. Since the State dropdown gets reduced to only the matched states after a Country selection, if you select a new Country that has states, you've now lost the original list of states, so the States dropdown comes up blank. This means if a user makes a mistake selecting their Country, they would need to reload the page in order to undo that mistake. Please correct me if I'm just implementing this wrong.
This is why we are saving them into a separate variable
How would you change/add to this script, if you wanted to get the respective cities of each state?
For the "grouped_collection_select", where is the ":states" parameter created? I use this one (both @sectors and @branches are filled in the controller):
<%= f.grouped_collection_select(:branch, @sectors, @branches, :sector, :id, :branch, include_blank: true) %>
But receive an error:
(eval):1: syntax error, unexpected $end group.#<ActiveRecord::Relation
Already found it, I just forgot to add "has_many :branches" to the sector model. Really stupid...
Anyone running into CSV import issues, please modify the seed.rb file as follows:
require 'csv'
puts "Importing countries..."
CSV.foreach(Rails.root.join("countries.csv"), headers: true, encoding: "ISO8859-1") do |row|
Country.create! do |country|
country.id = row[0]
country.name = row[1]
end
end
puts "Importing states..."
CSV.foreach(Rails.root.join("states.csv"), headers: true, encoding: "ISO8859-1") do |row|
State.create! do |state|
state.name = row[0]
state.country_id = row[2]
end
end
This fixes encoding issue, thanks!
But there is a problem. When try to record the data to db. There are lots of datas in ther e because of numbers of country and state field. For example you write name Bob, choose USA, and state NewYork. Datas are created many times Bob USA NewYork. Why?
I had a problem. When I changed the "country" dropdown sometimes it selected the wrong values for the "province" dropdown. Solved it like this:
Hey man, thank you, I had same problem.
When I save the data and want to edit them again, only the first select is shown.
The second select is on "style="display: none" regardless the right values is "option selected="selected".
Any suggestions?
Thanks ahead!
does this work for formtastic??? i can seem to make it work please help ..
I used this for an asset management app I'm writing.
Instead of countries/states, I use Makes/Models (which belong to an asset).
Anyway, if you are loading a record that has a make/model saved (or a country/state) then the model (state) will be hidden and you will have to change the make (country) to re-enable it. Then you will have to know it's saved value. So I changed it to only hide the model (state) if there is none saved.
jQuery -> loaded_model = $('#asset_model_id :selected').text() if loaded_model.length < 1 $('#asset_model_id').parent().parent().hide() models = $('#asset_model_id').html() $('#asset_make_id').change -> make = $('#asset_make_id :selected').text() escaped_make = make.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1') options = $(models).filter("optgroup[label='#{escaped_make}']").html() if options $('#asset_model_id').html(options) $('#asset_model_id').parent().parent().show() else $('#asset_model_id').empty() $('#asset_model_id').parent().parent().hide()I also used parent().parent() because I am using with SimpleForm
I like what you did here. This was bothering me too
The only problem is that when you show the second select, it shows all the options and not only the one it was supposed to.
I was able to "fix" the problem when editing an existing product and not having the second select or having it with all the options. It's looking pretty nasty but it works.
Does anyone how what I would do if I have multiple dynamic dropdown in the same form. Say I am allowing someone to pick country state for 3 people at the same time. Is there a way to scope the javascript to look within each person div? Otherwise, the selector would interfere with each other and nothing would work.
Did you ever find the answer for this Ben?
joining Ben & Sergioo - tried a bit with a for ... in loop on the parent element, but didn't got it yet.
Hi guys,
I'm a newbie so in my case my webpage is:
< label for="table_basket" >Basket</ label >
< select id="table_basket" name="table[basket]" >< option value="" >Please
select< /option >
< option value="1" >Awesome< /option >
< option value="2" >Normal< /option >< /select >
< label for="table_apple" >Apple< /label >
< select id="table_apple" name="table[apple]" >< option value="" >Please
select</ option >
< option value="1" >Green< /option >
< option value="1" >Red< /option >
< option value="2" >Yellow< /option >
< option value="2" >White< /option >< /select >
< input name="commit" type="submit" value="Create Table" />
in the app/views/apple/index.html.erb I have
<%= form_for @table do |f| %>
<%= f.label :basket %>
<%= f.collection_select :basket, @basket, :id, :name, {:prompt => true} %>
<%= f.label :comune %>
<%= f.collection_select :apple, @apple, :basket_id, :name, {:prompt => true} %>
<%= f.submit %>
<% end %>
And I change the apple.js.coffe file in this
jQuery ->
apple = $('#table_apple').html()
$('#table_basket').change ->
basket = $('#table_basket :selected').text()
options = $(apple).filter("[label=#{basket}]").html()
if options
$('#table_apple').html(options)
else
$('#table_apple').empty()
but it doesn't work I think the problem it's here in this line
options = $(apple).filter("[label=#{basket}]").html()
options doesn't get the 'value' of the option attribute in the select list menu
Is it a simple syntax error?
thank you in advance,
A
I followed this tutorial but am getting JQuery not defined in firebug. I looked at the application.js file and saw that the function was generated correctly. My application layout has javascript_include_tag before anything else is yielded. The funny thing is I have another Jquery function specified for another controller that's working perfectly fine. What am I doing wrong here?
Did you ever get an answer to this? I have the same situation.
Thanks.
Hello guys,
do you know how to do it with one drop down menu and hidden check boxes? When you click on "Yes" in drop down menu, it will display check boxes underneath but if you click on "never" it will not display anything underneath. Thank you
I could not get this script to work (new to javascript). I am using model User instead of Person. I copied the script as it is on this page and changed all 'person' to 'user'. I put the script is users.js.coffee in my assets/javascript folder. It seems to ignore the script. When I select a state it shows all the countries and related states instead of only displaying the states for the selected country.
I have my fields in a partial that is used both in new and edit.
Again I am new to scripting. I believe that all I have to do is to add the script and it should work. I do this when I want to add functions using Bootstrap. Any help would be appreciated.
I applied this concept to a has_many_through association. When I EDIT a page, the 'Country' is already selected but the 'State' list isn't filtered. I have to click to another 'Country' for the filter of the 'State' list to take effect.
Anyone know how to have the filtering kick-in upon page load?
Have you managed to solve this problem Faraz? I'm having the same issue..
Use #cbmeeks code above
Hey Guys i am a newbie to this...Based on this railcast i tried to do the following. Failed. Can anyone please help?
This is my View
`<%= f.association :product, :collection => Product.in_stock %>
<%= f.grouped_collection_select :batch_no, Product.in_stock, :store_opening_stocks, :title, :batch_no, :batch_no, :prompt => "Select Batch"%>`
This is Jquery.
jQuery(document).ready(function(){
var child = jQuery('.batch').html();
jQuery('.prod').change(function() {
var parent = jQuery('.prod :selected').text();
var escaped_parent = parent.replace(/([ #;&,.+*~\':"!^$[]()=>|\/@])/g, '\$1')
var options = jQuery(child).filter("optgroup[label='#{escaped_parent}']").html()
if (options) {
jQuery('.batch').html(options);
return jQuery('.batch').parent().show();
} else {
jQuery('.batch').empty();
}
});
});
Really need help been stuck for a week now. Any Help would be helpful.
You may get this error in Rails 3.2
N+1 Query detected
Country => [:states]
Add to your finder: :include => [:states]
N+1 Query method call stack
Add includes to Country as below
This isn't working for me in Internet Explorer 9...Changing the first select menu doesn't do anything. The second select menu remains hidden.
Chrome on Windows, and Safari, Firefox, and Chrome on OS X work fine. Any gotchas that you've found?
And the html...
It appears that this was an issue with
console.log, which I now realize wasn't intended to be in the final version of the code. When IE's "F12 Developer Tools" feature was enabled, the dynamic select menus worked as intended. I removed both instances ofconsole.logfrom the coffeescript file and the issue is gone, with and without F12 Developer Tools enabled. Gotcha on me.More on this here: http://stackoverflow.com/questions/11346091/i-e-craches-my-js-script-at-first-then-i-press-f12-and-it-works-beaultifully?lq=1
Great screencast. Will the grouped_collection_select work for a many to many relationship with multi-select? Any examples? Thank you.
What an awesome screencast. This also works with HABTM models as well! I wasn't expecting it to, but it worked :) Thank you!
I love Ryan's screencasts. I can't seem to get this working for me, however. The grouped_collection_select works, but my app seems to be ignoring the js.coffee file. I have the include tags in my application.html header, but still, no magic is happening. Does anyone know what I'm doing wrong?
invoices.js.coffee :
jQuery ->$('#invoice_facility_id').parent().hide()
facilities = $('#invoice_facility_id').html()
console.log(facilities)
$('#invoice_division_id').change ->
division = $('#invoice_division_id :selected').text()
options = $(facilitys).filter("optgroup[label=#{division}]").html()
console.log(options)
if options
$('#invoice_facility_id').html(options)
$('#invoice_facility_id').parent().show()
else
$('#invoice_facility_id').empty()
$('#invoice_facility_id').parent().hide()
_form.html.erb :
<label>Division:<font color="red">*</font></b></label><%= f.collection_select :division_id, Division.order(:division), :id, :division, :include_blank => true %>
<label>Facility:</label>
<%= f.grouped_collection_select :facility_id, Division.order(:division), :facilities, :division, :id, :facility, :include_blank => true %>
What changes are needed so that you can select the country and then select the city, instead of the state/region
This is how to support the edit form. Notice the trigger method.
Description: Execute all handlers and behaviors attached to the matched elements for the given event type.
didn't work for me. I have a select_tag which is not part of the form. I guess that is the problem
How can I filter the parent data by id and not by text?, I have a model that has 2 records with the same name, and when I select the parent it selects the other one with the same name.
Great screencast that I just revisited.
I'm using it with Twitter Bootstrap and Simple_Form. With this in play the parent().hide() function hides the dropdown box, but does not hide the label...
Now I can get round this by created a div around both and hiding that, but that seems to be a bit cumbersome. Looking at the page source I don't see any other obvious divs to use.
Any thoughts?
With this example, if we select United States or United kingdom it won't work. reason while filter state it is not able filter the value which have space. kindly someone help to get the values
I had the same error. I am using company names instead of countries. All of my companies have a space in the name. Was wondering if you possibly found a fix.
There's a problem with the escaping in firefox 10. Apparently it will escape the escaped_country variable again:
And it will break the filter...
Any idea what browser we actually need to escape first? I've tested with IE8 and chrome and they also both work with \' in the country name without escaping.
Wondering how could this be implemented using ActiveAdmin or Rails Admin.
This is a great railscast and I'm hoping to use this with States/Cities.
I'm still a bit new to rails and I don't understand the associations between the states and cities.
Say for instance I select the state of TX. I'd want only Houston, Austin, San Antonio, etc to show up. If I have a State and City model, how would I tie only those cities to the state.
I figured I could do
City.rb
belongs_to :state
State.rb
has_many :cities
And then put a state_id in the City model for the relationship.
But that would be a lot of manual work to get that done. Is there any way around this or a seed file that exists?
Maybe this can help those like Michael Elfassy, SMnetserv, pbaileyjr12 who have difficulty with double named countries.
On my app, everything worked fine until I accidentally 'bundle update' the gems.
After the bundle update, the double name countries (United States and United Kingdom) would not trigger and display the:
grouped_collection_select :state_id, Country.approved.includes(:states)
sidenote: bullet says to include states in the query.
I hope this helps:
First sign in through GitHub to post a comment.