See how to dynamically change a select menu based on another select menu using Javascript. In this episode everything is kept client side which leads to a more responsive user interface.
Wow, some very great tips on using Javascript in Rails. How about an episode on the efficient use of Javascript e.g. compression or caching of large libraries such as prototype?
Very cool, I'm making a site right now and I was using rjs, but got stuck at the how do I observe at load (my js skills are very poor). Now I get the onload update and faster updates :D However I am doing this on Rails 1.2.3, so there are a few differences. I had to name my view dynamic_states.rhtml, but I still put the :controller/:aciton.:format route, and it works just fine. I also had to get prototype 1.6.0 because I was getting a javascript error that there was no document.observe function. I also recommend getting the latest scriptaculous because without it I was getting a javascript recursion error on another part of my site. Now I just cross my fingers and hope that the new javascript libs and old Rails play nice together for the duration of the site being built :D
oops, I forgot to mention that I also had to put render :layout => false inside the dynamic_states controller so that I don't get all my html headers in what's supposed to be a javascript file
hey, u guys are doing a great job. i happened to come to ur site from www.techscreencast.com. They have a section full of videos on ror... some of the videos are from here... just wanted to say my thanks for ur efforts...
haha. I JUST implemented this a couple days ago (non-AJAX cascading selects). I'll have to revisit my code now that you've got this up. thanks for all the great screencasts
hey, i guess it would be easier (less js), more responsive (no dom-(re)generation), more accessible (optgroups do logic grouping), cleaner (no global vars in js) to just group the options and show or hide the group-of-options according to the selected country...
<select>
<optgroup label="..." id="x">
<option></option>
</optgroup>
here in brazil, for example, we always use something like this with States and Cities, and we have over 5000 cities and 27 states. for this case, isn´t ajax the best solution ?? could u show us how??
If anyone is interested, I have a plugin called applicability that does something like this automatically. Mine, however, is for turning parts of a form on or off based on a select menu.
Thanks for putting this up. Dynamic selects menus without buggy js plugins is exactly what I've been looking for. I'm having some trouble implementing though.
myhost/javascripts/dynamic_states.js renders normally. The script seems to load in the 'new' action given the html source of my view, though I noticed your helper method doesn't spit errors when given non-existent javascripts. The select id tags in dynamic_states line up with the ones in my the view. Still no action upon selecting country though. Any idea what I might be missing? I assume this works with remote_form_for?
Similar to Peter I'm having a few problems implementing this.
With implementation identical to yours navigating to
http://0.0.0.0:3000/javascripts/dynamic_show_requirements.js
renders:
"Missing template ....requirements.rhtml"
(nb. filename is "...requirements.js.erb")
Any quick tips as to how to get this moving?
Rails v 2.0.2 and Ruby v1.8.6
Scrap that - folks make sure you've got rails (including environment.rb) updated to latest and got your javascripts (as mentioned above updated to latest) using the command:
rake rails:update:javascripts
After having been working on something like this episode, rails seems unable to render my javascript and I need to update my routes and add the following line:
Ryan. I have followed the tutorial to the letter and i still can't get it to work. When i look at the javascript file /javascripts/dynamic/states.js i get the same as you do. However when i load a page the dynamicness just doesn't work... any ideas?
Hi Ryan,
thanks for your wonderful series. We had some trouble with your javascript. If there is only one state in a selected country, your script displayed that state twice. To fix that we changed "options.length = 1;" to "options.length = 0;" and also the if clause to "if(options.length == 0)"
Great tutorial. However, if a validation error occurs on one of the fields on the same page and the page is re-rendered with an error message the state drop down gets messed up. The prompt message is no longer there and the first state in the DB is there instead. Any ideas....?
How can it work with your 3-part complex forms casts?
When you add new task and each task on page will have those related dropdown how you refer to them?
When you add new task the div that you create in "simplify_views_for_rails_2.0" has id="new_task".
Each has id="new_task" and it is mark-up error.
Can you figure that out, cause that will be helpful!:)
ps. great railscasts! continue!
Ok I've solved it.
You got to modify your js.erb file, so it won't observe since you can't get the elements with the same ID from the js file.
So in partial with countries and states do:
f.collection_select(:country, Country.find(:all), :id, :name, {:include_blank => true }, :onchange => "collectionSelected(this);")
And your js.erb will look like:
// array generation
function collectionSelected(e) {
country_id = e.getValue();
options = e.next(1).options;
options.length = 1;
states.each(function(model) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
}
I would love to see this same problem solved using Ajax. I am doing the exact same thing you show here (country -> states), however, I've put together a couple of lookup tables (using the United Nations website) that has every country, and all the "states" for each and every country.
This "state" list contains about 3500 records and I just don't think that I want to use javascript for that every single time.
So, I humbly ask if you would do the same Railscast to show the Ajax method as an alternative.
Thanks first.
I've managed to make this work, but had two problems.
First, a non-related state option will display for every country, this is solved by modifying the first options.length = 1; to options.length = 0;
The other problem: On edit page, which also is using these codes, I find the saved state information is lost. The selector's default value fixs to the first option available for the country. I have no idea to fix this.
FireBug reports:
document.observe is not a function
[Break on this error] document.observe('dom:loaded', function() {
check you have included <%= javascript_include_tag 'prototype' %> in your layout used in the edit page otherwise you need to check your $('person_country_id').observe('change', countrySelected); and ensure that person_country_id is the correct id in your edit view.
Thanks for the great podcast. I am still very new at programming in Rails, so please forgive this comment if it's already obvious to everyone else.
I was using Prototype Javascript 1.5.0 as part of RailsI so I too was getting the "document.observe is not a function" error message. I decided to upgrade to "RailsII" which includes Prototype 1.6.0.
But the error persisted, until I noticed that the "public/javascripts" folder in my application code tree that I had copied over from RailsI included the older versions of the Prototype library.
Just copying the newer Prototype library into the "public/javascripts" folder seemed to do the trick.
Hope this is helpful.
Internet Explorer needs var added to new variables to avoid the 'Object or method not found'
// javascripts/dynamic_states.js.erb
var states = new Array();
<% for state in @states -%>
states.push(new Array(<%= state.country_id %>, '<%=h state.name %>', <%= state.id %>));
<% end -%>
function countrySelected() {
var country_id = $('person_country_id').getValue();
var options = $('person_state_id').options;
options.length = 1;
states.each(function(state) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
if (options.length == 1) {
$('state_field').hide();
} else {
$('state_field').show();
}
}
Is it me, or is there a lot of stuff missing if you don't follow these tutorials in order?
I tried following along with this one (Dynamic Select Menus) and all of a sudden kept running into things that were not mentioned in the video: for example, creating the "new" action, creating the Countries and States tables in the db, modifying the routes.rb file (OK, that one was mentioned, just late in the video), etc.
It's impossible to follow along when you don't have the groundwork covered, and now I don't know where the info is that I missed.
I have give you approach a try and it works pretty fine.
One thing though is that this way you end up with a two round call to rails to fulfill the request, one call to the people_controller and another to the javascripts_controller, with the repeating of bussiness processing if the thing get too complex.
If you want to try another approach this one looks fine:
http://railsenvy.com/2008/1/3/unobtrusive-javascript
oops sorry (I've made a two round posting here :-> )
@martin:
las rutas por defecto de rails funcionan, fijate si no las has eliminado en alguna refactorizacion REST, sino hay otro screencast sobre custom_routes en REST
sorry about posting in spanish, but:
en este
<a href="http://qvitta.net/articles/2008/04/24/javascript-no-obstrusivo-o-cuando-ajax-es-un-problema">post comento un poco los problemas de ajax, este enfoque y demas</a> en español! si os lo quereis mirar.
What if I want to record the country name and state name in the person model (rather than their id?) But I still want to record country_id in the state model. Can anyone point me in the right direction?
I love these tips! It would be very nice if you could package the files for examination. I'm having trouble understanding were your view code includes the state field.
I made some progress and discovered that my problem is trying to use this technique with a DIV that gets updated with RJS. I can't seem to get the javascript to be interpreted unless I put it on the main page, but then the observed fields are not available.
Any ideas on how to use this technique for partials that come and go with RJS/Ajax?
Is it possible to use this same concept to build a list to use with Drag and Drop? I'd like to load the lists and display only those states related to the country, but instead of a select list, the user is dragging and dropping values to create a list of items.
If so, any ideas on how to modify the function countrySelected to create my list elements?
I am using the Rails 1.2.3, and follow the instruction that clouder said. But it looks like I still miss the dynamic_states.js, even I have correct output in http://localhost:3000/javascripts/dynamic_states. Could someone give any suggestion? Thanks!
I have tried everything in the tutorial and the comments including May 22 08 comment by "pi_p master" for respond_to do format etc. and here is my predicament; my application works on my development machine just fine; when I transport it to my production environment it does not call the javascripts controller; I have the following error : <script type="text/javascript" src="/javascripts/dynamic_units.js">
1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
2<html><head>
3<title>404 Not Found</title>
4</head><body>
5<h1>Not Found</h1>
6<p>The requested URL /javascripts/dynamic_units.js was not found on this server.</p>
7</body></html>
Now I have even tried putting in explicitly map.connect ':controller/:action.:format'
I am having the same exact problem as Captain Zhan. This script totally borks out on the edit action. It forgets the state I selected even though I see it clearly saved in the database.
All of my javascripts are definitely included and the script still works - if I change the country, the state list changes, but the initial load is screwed up and automatically selects the first state in the list, instead of the state saved in the DB.
As a temporary solution, I simply do not load the script i current action is edit, but thats not too cool of a fix.
For those of you pulling your hair out with this complicated solution, there is an excellent pluin that handles all this fun stuff in just a few lines of helper code.
"Check it out!":http://dvisionfactory.googlecode.com/svn/rails/plugins/related_select_forms/
Hi, I'm trying to get this up and running in a scenario in which a person has a state and a state has a country, but a person doesn't have a country except through the state. In this case, the collection_select for country won't work. I'm trying to use a combined call to select_tag and options_from_collection_select to give me just the tags, but I haven't been able to get it to work yet.
I've also taken pimpmaster's suggestion about formatting, and should also mention that as with Vysogot, I'm trying to do this with something structurally similar to the projects/tasks application which is explored in the three part complex forms series. I haven't gotten too deep into trying Vysogot's solution for this to see if that get's things working, but I figured I would see if anyone could could me a quick suggestion on approach - I'll post more when I figure out more.
I was able to successfully implement this with the 3-part complex forms application. Vysogot's solution worked, but I had to make a couple of further modifications. Here is the code from my _task partial
<label for="task_state_id">State or Province:</label>
<%= task_form.collection_select :state_id, State.find(:all), :id, :name, :prompt => "Select a State" %>
</p>
...
Here's what I changed:
-I had to call :country_id (not :country) in the collection_select
-I put the collection_selects in the the same <p> element so that the call to .next() works properly.
-I put the :onchange call in {} brackets
-'model' in the def of collectionSelected() should have been 'state'
I think that that's it for the complex forms application. I'm still not sure how to get this to work with my application, since as I mentioned I can't use collection_select, as what will effectively be the person in my application has a state, but a country only through a state. I'll keep working on it, but if anyone knows what to use instead of a collection_select I would appreciate a comment on it.
Oh, and thanks to Ryan and everyone else who helps everyone out here - Awesome!
Alright, so I got it to work using options_from_from_collection_for_select to get the options and then feeding them into a select_tag method. It works, but a) it seems like there is a prettier way to do it and b) I'm not sure how to specify a prompt. I've tried putting :prompt => "Select a such and Such" both at the end of the select_tag call and the options_ from_col.. call, and neither works. If anyone has solutions to these minor queries, answers would be welcome and appreciated.
I'm having some trouble with the edit using this method.
For example:
When I go to the edit, and i have several countries associated to it's continents, it keeps the value selected (for example China for the Asian continent). When I change the continent in the parent select it replaces all the select but not the prompted edit value (in this case China).
The question is, how can I replace that first value in the edit view?
I am using the Rails 1.2.3, and follow the instruction that clouder said. But it looks like I still miss the dynamic_states.js, even I have correct output in http://localhost:3000/javascripts/dynamic_states. Could someone give any suggestion? Thanks!
It's probably better to use double quotes around the state name in the js file since a state name might contain a single quote. Ex. "Provence-Alpes-Cote d'Azur"
In dynamic_states.js change '<%=h state.name %>' to "<%=h state.name %>"
The suggested code doesn't select the state from the drop-down if it's already selected for me. Not sure what I'm doing differently from the suggested code.
Adding an if statement and a few parameters to the 'new Option(name, id, false, true)' are what worked: http://gist.github.com/45324
Thanks! I have successfully used the feature (including cache in next episode) for a model.
I have a problem to reuse this js for many models. Because we specify the model name 'person' in RJS like 'person_country_id', the f.select and f.collection_select always automatically set the ID for us. I want to get rid of the "person_" part. But
How to get rid of the "person_" part by manually specify the DOM ID in
f.select or f.collection_select
Awesome thanks for the tutorial and everyone's comments for the help. Just to let everyone else know to get this to work in the edit view I had to do the following additions:
comment #26. Andreas and Björn
and
comment #61. Peer Allan (this code goes in the edit view and for some reason for me I couldn't use a partial for the form...)
I don't care that I am the 160th person to say some variation of this...you are awesome! Just saved me hours, and got some new rails code architecture tips
In response to Stephen's (29.) issue with error messages messing up the second select, I used Peer's solution (61.) placed in the view template, along with a line to update that first option in the select so it didn't show the first option in the list: http://gist.github.com/96784
@pimpmaster (no. 51),
Thanks ever so much for taking the time to post your solution here. I was tearing my hair out as this wouldn't work until I read your suggestion (adding map.js ':controller/:action.:format' to routes.rb).
Cheers buddy.
an issue i came across is when using nginx as a front for live server. nginx conf file is set to redirect all the /javascripts/ request to the public/javascripts folder.
this means the call to the dynamic files will never return the correct file.
Internet Explorer needs var added to new variables to avoid the 'Object or method not found'
// javascripts/dynamic_states.js.erb
var states = new Array();
<% for state in @states -%>
states.push(new Array(<%= state.country_id %>, '<%=h state.name %>', <%= state.id %>));
<% end -%>
function countrySelected() {
var country_id = $('person_country_id').getValue();
var options = $('person_state_id').options;
options.length = 1;
states.each(function(state) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
if (options.length == 1) {
$('state_field').hide();
} else {
$('state_field').show();
}
}
I have this running fine. However, it seems that the javascript is either running before the controller has finished running, or the javascript is not able to use variables form the controller
This will generate all the needed javascript - with the exception of the main function, that should be included on the layout.
Note that the current implementation downloads everything at the begining on a big javascript array; if you are looking for an AJAX solution you'll have to look elsewhere - for now :) at least.
1) care to respond to some of them at least?
2) a non-fully client side approach is to use Ajax. Could you please do a railscast on how to achieve the same effect using ajax?
One thing is not clear to me. Is the action dynamic_states expected to be called manually everytime the contries/states get changed? If not, how does it get invoked? In the tutorial, Ryan invoked the method directly using the URL. If that is not done, is this still going to work?
Checkout my solution that neads no JavaScript code writing, and requires fever lines of code: http://programmers-blog.com/2009/11/12/dependant-dropdowns-select-menus-using-rails
Anyone have any experience doing dynamic selects menus with very large numbers of option data? I've tried just JS and Ajax and both options are very slow on the first change. My first select has about 700 options, the second over 5000.
Thanks for this tutorial. I've been looking for some time for a decent one on dynamic select menus. You'd be surprised how much trash info there is out there.<a href="http://oynetwork.com/">lead</a>
Moin moin! Wirklich schöne Seite die ihr da habt.Bin schon ein paar mal auf eurer Seite gewesen und jetzt hab ich mir gedacht, ich schreib euch mal was nettes ins Gästebuch. Also echt toll was ihr hier gemacht habt. Macht weiter so. Ich würde ich mich über einen Gegenbesuch auf meiner Webseite "Urlaub auf Sylt oder an der Ostsee" sehr freuen.
I've implemented all the code, but the dynamic menu isn't working - no errors are thrown, but the first selection list has no impact on the second selection list (and the second one isn't even hidden, either).
Is there something different about Rails 2.3.5 that I should consider??
But I have a question for anyone... I implemented the dynamic select menus just fine. But I want my final select to populate a "description" field that is not editable. Anyone know how to do that?
I'm trying to implement this on an edit page (rather than a new page) and in my application I have Buildings and Rooms instead of Countries and States, but the relationship is basically the same.
It is not working for me. Regardless of which Building (country) I select, the list of Rooms (states) does not change. I have no idea what the problem is.
Hi. This was a great help. Thanks for that. Just one little problem that I am facing. The second drop down list that is displayed, is not sorted. I want to sort it alphabetically. Right now, it sorts it by id. Any ideas?
how to dynamic update another selector when a selector changes by ajax on ruby?
because there are not load all select info when page loaded, should call server to get another select reload when a selector changes.
e.g I used country_select and state_select plugins. I don't know how to make state_select dynamic update after country_select changes.
Mac Martine - can you elaborate on how you got this working for rails 3? I have everything loaded with no errors but the javascript doesn't seem to run.
These drop down menus are really often used these days.. A lot of websites do use them. Rail seems to be a management system like drupal.
A cool slide menu is used at this site here http://www.nitis-flotte-kindermoden.de Its uses another system (a shopping system) from cosmoshop.
But I think all systems are based of Javascript?!
hey! first comment comes from germany. great episode, ryan! every monday 9:00 in the morning, it's time to watch railscasts! philipp
The <code>content_for(:head)</code> is very sweet!
I was just going to figure out how to do this today! Thanks for saving me time and effort once again!!
Wow, some very great tips on using Javascript in Rails. How about an episode on the efficient use of Javascript e.g. compression or caching of large libraries such as prototype?
Thanks!
Chris
Railscast is like Knoppers, every morning at 9:30 in Poland :)
Very cool, I'm making a site right now and I was using rjs, but got stuck at the how do I observe at load (my js skills are very poor). Now I get the onload update and faster updates :D However I am doing this on Rails 1.2.3, so there are a few differences. I had to name my view dynamic_states.rhtml, but I still put the :controller/:aciton.:format route, and it works just fine. I also had to get prototype 1.6.0 because I was getting a javascript error that there was no document.observe function. I also recommend getting the latest scriptaculous because without it I was getting a javascript recursion error on another part of my site. Now I just cross my fingers and hope that the new javascript libs and old Rails play nice together for the duration of the site being built :D
oops, I forgot to mention that I also had to put render :layout => false inside the dynamic_states controller so that I don't get all my html headers in what's supposed to be a javascript file
hey, u guys are doing a great job. i happened to come to ur site from www.techscreencast.com. They have a section full of videos on ror... some of the videos are from here... just wanted to say my thanks for ur efforts...
haha. I JUST implemented this a couple days ago (non-AJAX cascading selects). I'll have to revisit my code now that you've got this up. thanks for all the great screencasts
Ryan - thanks a lot for doing this episode. It's been hard to find a solid tutorial on dynamic select menus.
Why can't I see the video on my iphone? I only hear the audio. I'm subscribed to the ipod version.
Anyhow, keep up the good work, nice podcasts! I wish I could watch them at the gym, though ;-)
hey, i guess it would be easier (less js), more responsive (no dom-(re)generation), more accessible (optgroups do logic grouping), cleaner (no global vars in js) to just group the options and show or hide the group-of-options according to the selected country...
<select>
<optgroup label="..." id="x">
<option></option>
</optgroup>
<optgroup label="..." id="y">
<option></option>
</optgroup>
<optgroup label="..." id="z">
<option></option>
</optgroup>
</select>
... but as always... thank you for your efforts
great job/idea!!
here in brazil, for example, we always use something like this with States and Cities, and we have over 5000 cities and 27 states. for this case, isn´t ajax the best solution ?? could u show us how??
congratulations for this screencast!!
If anyone is interested, I have a plugin called applicability that does something like this automatically. Mine, however, is for turning parts of a form on or off based on a select menu.
http://code.google.com/p/applicability/
Jon
Thank you Ryan, that's one more neat screencast which came exactly when I needed it most.
Unfortunately there is at least one major issue:
What if you want to edit the stuff later? The child item won't be select, you have to choose again :(
Thanks for putting this up. Dynamic selects menus without buggy js plugins is exactly what I've been looking for. I'm having some trouble implementing though.
myhost/javascripts/dynamic_states.js renders normally. The script seems to load in the 'new' action given the html source of my view, though I noticed your helper method doesn't spit errors when given non-existent javascripts. The select id tags in dynamic_states line up with the ones in my the view. Still no action upon selecting country though. Any idea what I might be missing? I assume this works with remote_form_for?
Similar to Peter I'm having a few problems implementing this.
With implementation identical to yours navigating to
http://0.0.0.0:3000/javascripts/dynamic_show_requirements.js
renders:
"Missing template ....requirements.rhtml"
(nb. filename is "...requirements.js.erb")
Any quick tips as to how to get this moving?
Rails v 2.0.2 and Ruby v1.8.6
Thanks for the podcast! :)
Scrap that - folks make sure you've got rails (including environment.rb) updated to latest and got your javascripts (as mentioned above updated to latest) using the command:
rake rails:update:javascripts
Thanks Ryan!
Taking out "countrySelected();" in the amended javascript makes this work for my app on rails 2.0.2.
I would like to filter the states list by the pre-selected country though. What might I be missing?
After having been working on something like this episode, rails seems unable to render my javascript and I need to update my routes and add the following line:
<code> map.connect ':controller/:action.:format'</code>
Great article though...
Sorry, it's not a great article but a great rails screencast. :)
Just as a note, all javascripts should be included at the bottom of the page right before the body close tag. It's better performance wise.
Thanks for this episode
What's the use of "*files" in the helper method, looks like some kind of dereferenced pointer to me - I'm certainly not a ruby guru ;-)
Ryan. I have followed the tutorial to the letter and i still can't get it to work. When i look at the javascript file /javascripts/dynamic/states.js i get the same as you do. However when i load a page the dynamicness just doesn't work... any ideas?
Hi Ryan,
thanks for your wonderful series. We had some trouble with your javascript. If there is only one state in a selected country, your script displayed that state twice. To fix that we changed "options.length = 1;" to "options.length = 0;" and also the if clause to "if(options.length == 0)"
Hello Ryan,
great tutorial, exactly what I was looking for.
Thanks for this and all your terrific podcasts
Is it possible to implement the same logic using 3 dynamic menus?
Hey Ryan,
Great tutorial. However, if a validation error occurs on one of the fields on the same page and the page is re-rendered with an error message the state drop down gets messed up. The prompt message is no longer there and the first state in the DB is there instead. Any ideas....?
How can it work with your 3-part complex forms casts?
When you add new task and each task on page will have those related dropdown how you refer to them?
When you add new task the div that you create in "simplify_views_for_rails_2.0" has id="new_task".
Each has id="new_task" and it is mark-up error.
Can you figure that out, cause that will be helpful!:)
ps. great railscasts! continue!
Ok I've solved it.
You got to modify your js.erb file, so it won't observe since you can't get the elements with the same ID from the js file.
So in partial with countries and states do:
f.collection_select(:country, Country.find(:all), :id, :name, {:include_blank => true }, :onchange => "collectionSelected(this);")
And your js.erb will look like:
// array generation
function collectionSelected(e) {
country_id = e.getValue();
options = e.next(1).options;
options.length = 1;
states.each(function(model) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
}
and thats it :)
Interesting, as usual.
I would love to see this same problem solved using Ajax. I am doing the exact same thing you show here (country -> states), however, I've put together a couple of lookup tables (using the United Nations website) that has every country, and all the "states" for each and every country.
This "state" list contains about 3500 records and I just don't think that I want to use javascript for that every single time.
So, I humbly ask if you would do the same Railscast to show the Ajax method as an alternative.
Thanks!
B.
Thanks first.
I've managed to make this work, but had two problems.
First, a non-related state option will display for every country, this is solved by modifying the first options.length = 1; to options.length = 0;
The other problem: On edit page, which also is using these codes, I find the saved state information is lost. The selector's default value fixs to the first option available for the country. I have no idea to fix this.
FireBug reports:
document.observe is not a function
[Break on this error] document.observe('dom:loaded', function() {
@Captain Zhan
check you have included <%= javascript_include_tag 'prototype' %> in your layout used in the edit page otherwise you need to check your $('person_country_id').observe('change', countrySelected); and ensure that person_country_id is the correct id in your edit view.
Thanks for the great podcast. I am still very new at programming in Rails, so please forgive this comment if it's already obvious to everyone else.
I was using Prototype Javascript 1.5.0 as part of RailsI so I too was getting the "document.observe is not a function" error message. I decided to upgrade to "RailsII" which includes Prototype 1.6.0.
But the error persisted, until I noticed that the "public/javascripts" folder in my application code tree that I had copied over from RailsI included the older versions of the Prototype library.
Just copying the newer Prototype library into the "public/javascripts" folder seemed to do the trick.
Hope this is helpful.
Internet Explorer needs var added to new variables to avoid the 'Object or method not found'
// javascripts/dynamic_states.js.erb
var states = new Array();
<% for state in @states -%>
states.push(new Array(<%= state.country_id %>, '<%=h state.name %>', <%= state.id %>));
<% end -%>
function countrySelected() {
var country_id = $('person_country_id').getValue();
var options = $('person_state_id').options;
options.length = 1;
states.each(function(state) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
if (options.length == 1) {
$('state_field').hide();
} else {
$('state_field').show();
}
}
document.observe('dom:loaded', function() {
countrySelected();
$('person_country_id').observe('change', countrySelected);
});
Is it me, or is there a lot of stuff missing if you don't follow these tutorials in order?
I tried following along with this one (Dynamic Select Menus) and all of a sudden kept running into things that were not mentioned in the video: for example, creating the "new" action, creating the Countries and States tables in the db, modifying the routes.rb file (OK, that one was mentioned, just late in the video), etc.
It's impossible to follow along when you don't have the groundwork covered, and now I don't know where the info is that I missed.
por favor me dicen cuales serian las rutas routes.rb
me genera el siguiente error:
ActionController::RoutingError (No route matches "/javascripts/dynamic_states.js" with {:method=>:get}):
A mi tambien me sucede lo mismo, lo que sucede al parecer es que en el recorrido del video Ryan Bates olvido modificar las rutas.
Hey guys this is the solution, match "javascripts/dynamic_states" => "javascripts#dynamic_states"
gracias. es posible ajustarlos para dos combobox mas?
saludos
hi,
great work.
I have give you approach a try and it works pretty fine.
One thing though is that this way you end up with a two round call to rails to fulfill the request, one call to the people_controller and another to the javascripts_controller, with the repeating of bussiness processing if the thing get too complex.
If you want to try another approach this one looks fine:
http://railsenvy.com/2008/1/3/unobtrusive-javascript
keep on the good work
oops sorry (I've made a two round posting here :-> )
@martin:
las rutas por defecto de rails funcionan, fijate si no las has eliminado en alguna refactorizacion REST, sino hay otro screencast sobre custom_routes en REST
that's it
sorry about posting in spanish, but:
en este
<a href="http://qvitta.net/articles/2008/04/24/javascript-no-obstrusivo-o-cuando-ajax-es-un-problema">post comento un poco los problemas de ajax, este enfoque y demas</a> en español! si os lo quereis mirar.
Great stuff Ryan!
I have a question though (for anyone).
What if I want to record the country name and state name in the person model (rather than their id?) But I still want to record country_id in the state model. Can anyone point me in the right direction?
I love these tips! It would be very nice if you could package the files for examination. I'm having trouble understanding were your view code includes the state field.
I made some progress and discovered that my problem is trying to use this technique with a DIV that gets updated with RJS. I can't seem to get the javascript to be interpreted unless I put it on the main page, but then the observed fields are not available.
Any ideas on how to use this technique for partials that come and go with RJS/Ajax?
Is it possible to use this same concept to build a list to use with Drag and Drop? I'd like to load the lists and display only those states related to the country, but instead of a select list, the user is dragging and dropping values to create a list of items.
If so, any ideas on how to modify the function countrySelected to create my list elements?
THANKS!
I am using the Rails 1.2.3, and follow the instruction that clouder said. But it looks like I still miss the dynamic_states.js, even I have correct output in http://localhost:3000/javascripts/dynamic_states. Could someone give any suggestion? Thanks!
FYI: I had problems in Rails 2.0.2 until I added this line to that dynamic states action
respond_to do |format|
format.js
end
I also had to add this to routes.rb:
map.js ':controller/:action.:format'
And now everything works
Hope it helps someone :)
Extremely useful, thanks! This just saved me a couple of hours of searching the net. Thanks, Ryan!
I have tried everything in the tutorial and the comments including May 22 08 comment by "pi_p master" for respond_to do format etc. and here is my predicament; my application works on my development machine just fine; when I transport it to my production environment it does not call the javascripts controller; I have the following error : <script type="text/javascript" src="/javascripts/dynamic_units.js">
1<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
2<html><head>
3<title>404 Not Found</title>
4</head><body>
5<h1>Not Found</h1>
6<p>The requested URL /javascripts/dynamic_units.js was not found on this server.</p>
7</body></html>
Now I have even tried putting in explicitly map.connect ':controller/:action.:format'
as well as :
map.js '/javascripts/dynamic_units.js' , :controller=>'javascripts', :action =>'dynamic_units'
and whatever permutation I could fathom but to no avail. Help please.
I am having the same exact problem as Captain Zhan. This script totally borks out on the edit action. It forgets the state I selected even though I see it clearly saved in the database.
All of my javascripts are definitely included and the script still works - if I change the country, the state list changes, but the initial load is screwed up and automatically selects the first state in the list, instead of the state saved in the DB.
As a temporary solution, I simply do not load the script i current action is edit, but thats not too cool of a fix.
Anyone else deal with this?
Where is Ryan???? *shines Bat Signal*
For those of you pulling your hair out with this complicated solution, there is an excellent pluin that handles all this fun stuff in just a few lines of helper code.
"Check it out!":http://dvisionfactory.googlecode.com/svn/rails/plugins/related_select_forms/
It also works well on edit!
Tanks for this screencast!
@Harry J The plugin you mentioned works great!
Having said that, I also think the screencast is excellent, because it is all about learning and seeing new or 'unknown' techniques.
Hola tengo un problema con este tutorial. Hice exactamente cada paso pero aplicado a mi proyecto y me sale el siguiente error.
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
Extracted source (around line #2):
1: var versions = new Array();
2: <% for producto in @productos -%>
3: versions.push(new Array(<%= version.producto_id %>, '<%=h version.verprod %>', <%= version.id %>));
4: <% end -%>
5:
hey guys,
I am trying to do this with a has_many :through relationship.
job, division, job_division
i am unsure whether to use the job_division 'join' table as the model in the js.erb file
Any ideas?
Hi, I'm trying to get this up and running in a scenario in which a person has a state and a state has a country, but a person doesn't have a country except through the state. In this case, the collection_select for country won't work. I'm trying to use a combined call to select_tag and options_from_collection_select to give me just the tags, but I haven't been able to get it to work yet.
I've also taken pimpmaster's suggestion about formatting, and should also mention that as with Vysogot, I'm trying to do this with something structurally similar to the projects/tasks application which is explored in the three part complex forms series. I haven't gotten too deep into trying Vysogot's solution for this to see if that get's things working, but I figured I would see if anyone could could me a quick suggestion on approach - I'll post more when I figure out more.
Cheers
In relation to the edit form not remembering the child. I got around it by added another onload observer to set the value.
<script>
document.observe('dom:loaded', function() {
$('person_state_id').value = <%= @person.state_id %>;
});
</script>
Not the most elegant, but it works! Good Luck!
I was able to successfully implement this with the 3-part complex forms application. Vysogot's solution worked, but I had to make a couple of further modifications. Here is the code from my _task partial
...
<label for="task_country_id">Country:</label>
<%= task_form.collection_select :country_id, Country.find(:all), :id, :name, {:prompt => "Select a Country"}, {:onchange => "collectionSelected(this);"} %>
<label for="task_state_id">State or Province:</label>
<%= task_form.collection_select :state_id, State.find(:all), :id, :name, :prompt => "Select a State" %>
</p>
...
Here's what I changed:
-I had to call :country_id (not :country) in the collection_select
-I put the collection_selects in the the same <p> element so that the call to .next() works properly.
-I put the :onchange call in {} brackets
-'model' in the def of collectionSelected() should have been 'state'
I think that that's it for the complex forms application. I'm still not sure how to get this to work with my application, since as I mentioned I can't use collection_select, as what will effectively be the person in my application has a state, but a country only through a state. I'll keep working on it, but if anyone knows what to use instead of a collection_select I would appreciate a comment on it.
Oh, and thanks to Ryan and everyone else who helps everyone out here - Awesome!
Alright, so I got it to work using options_from_from_collection_for_select to get the options and then feeding them into a select_tag method. It works, but a) it seems like there is a prettier way to do it and b) I'm not sure how to specify a prompt. I've tried putting :prompt => "Select a such and Such" both at the end of the select_tag call and the options_ from_col.. call, and neither works. If anyone has solutions to these minor queries, answers would be welcome and appreciated.
Thanks again!
I'm having some trouble with the edit using this method.
For example:
When I go to the edit, and i have several countries associated to it's continents, it keeps the value selected (for example China for the Asian continent). When I change the continent in the parent select it replaces all the select but not the prompted edit value (in this case China).
The question is, how can I replace that first value in the edit view?
nice screencast! thanks!
Just as a note, all javascripts should be included at the bottom of the page right before the body close tag. It's better performance wise.
I am using the Rails 1.2.3, and follow the instruction that clouder said. But it looks like I still miss the dynamic_states.js, even I have correct output in http://localhost:3000/javascripts/dynamic_states. Could someone give any suggestion? Thanks!
@Werbeagentur,
Try http://localhost:3000/javascripts/dynamic_states.js
@Werbeagentur,
Sorry! I misunderstood your question! I had the same problem actually. What does your HTML look like for your "states" in your form?
Great work there..
I get this error. I'm using rails 2.1
No route matches "/javascripts/dynamics_states.js" with {:method=>:get}
[@Matt, @Herbalife] It does work with 2.1. There's a route you have to set - see http://gist.github.com/12391
Sorry! I misunderstood your question! I had the same problem actually. What does your HTML look like for your "states" in your form?
@ Johny: many thanks!
Very complicated but I´ll try it!
Thank you.
Not to easy. But if you read carefully it works
Very interesting write up. But its difficult to understand!
thanks for the awesome script.. i'm just wondering which one is better compare to using ajax..
Seems a little complicated first, but when reading it carefully, it works...
This episode was great! Thanks.
ingilizce tercüme
Very interesting write up.
Good very good!!
Great tutorial but not easy to understand. Thanks a lot for our help.
This broke for me when upgrading to 2.2.2
The content_for capture in application_helper.rb doesn't fail, but it also doesn't insert the stylesheet/javascript into the template.
Any ideas?
This description really helped me a lot. Thanks. ;)
Thanks Ryan,I think this is one of the most wonderful sites. I have great admiration for you.Gayrimenkul degerleme ekspertiz
This broke for me when upgrading to 4 5 kiralık satılık emlak gayrimenkul
You really helped me out with this. Thank you very much!
I searched for dynamic menus in Ruby and your article helps me a lot... Thanks for posting it. Great help!
can this be used in os commerce?
I should try those codes, thanks
Great job and good idea !
Congratulations for this screencast !! Best Regards Holz-Export
The first time I tried this I was using Rails 1.2.3 so I skipped the js.erb file and implemented the javascript directly in the html page.
Now I'm working on another project using Rails 2.2.2 and was able to implement the way you show. It works great.
Thanks to Peer Allan for sharing how he fixed the edit form issue.
Any ideas why I'm getting "Missing layout layouts/application.erb in view path /myapp/app/views"?
For some reason when rendering the .js template my app is trying to use the wrong (non-existant) layout mentioned above.
It's probably better to use double quotes around the state name in the js file since a state name might contain a single quote. Ex. "Provence-Alpes-Cote d'Azur"
In dynamic_states.js change '<%=h state.name %>' to "<%=h state.name %>"
Any Idea how to include javascript file from a partial loaded via rjs ?
Thanks !
To answer my question post 131, couldn't find a way to execute javascript_include_tag in a partial loaded through .rjs.
I used javascript_tag straight in the view to refresh js global variable.
The suggested code doesn't select the state from the drop-down if it's already selected for me. Not sure what I'm doing differently from the suggested code.
Adding an if statement and a few parameters to the 'new Option(name, id, false, true)' are what worked: http://gist.github.com/45324
I aggree. Amazing and helpful. Love Rails ;)
@Stephen Tudor
thanks for the tip in post 78, helped me get this working in Rails2.2.2... great tutorial btw... spot on!!
"[@Matt, @Herbalife] It does work with 2.1. There's a route you have to set - see http://gist.github.com/12391"
Thanks! I have successfully used the feature (including cache in next episode) for a model.
I have a problem to reuse this js for many models. Because we specify the model name 'person' in RJS like 'person_country_id', the f.select and f.collection_select always automatically set the ID for us. I want to get rid of the "person_" part. But
How to get rid of the "person_" part by manually specify the DOM ID in
f.select or f.collection_select
Hope I make myself understood.
I'm still not able to get this to work in 2.2.2. I have added the following to my router per #78
map.js ':controller/:action.:format'
I am using this with a partial and so am not sure if this is affecting anything.
Could anyon who has got this working in 2.2.2 share the code?
cheers
Michael
Awesome thanks for the tutorial and everyone's comments for the help. Just to let everyone else know to get this to work in the edit view I had to do the following additions:
comment #26. Andreas and Björn
and
comment #61. Peer Allan (this code goes in the edit view and for some reason for me I couldn't use a partial for the form...)
Hope this helps anyone. thanks again Ryan!!
Thanks for posting it's beeen a great help
I don't care that I am the 160th person to say some variation of this...you are awesome! Just saved me hours, and got some new rails code architecture tips
In response to Stephen's (29.) issue with error messages messing up the second select, I used Peer's solution (61.) placed in the view template, along with a line to update that first option in the select so it didn't show the first option in the list: http://gist.github.com/96784
@pimpmaster (no. 51),
Thanks ever so much for taking the time to post your solution here. I was tearing my hair out as this wouldn't work until I read your suggestion (adding map.js ':controller/:action.:format' to routes.rb).
Cheers buddy.
Thanks for posting. Great Work.
I think that the use of "*files" in the helper method, looks like some kind of dereferenced pointer , but is a kind of understandig. God work - thx!
JOEY
Could it be possible to send parameters to the javascript functions ?
Nice RailsCast. I just have a quick question, what if i want to use the same fields in multiple forms, how will i achieve that?
This one is for jQuery
<script src="http://gist.github.com/122221.js"></script>
Is there anyway to get this to work with ajax, because i need to load 4000 cities. I have searched every where and found nothing. Please Help
Your screencast for dynamic select menus helped me. Thx for sharing it!
I am really looking for a JQuery solution for this as the current code as is, is not working properly.
I do not know JQuery much so any help in fixing this will be helpful.
Thanks for Posting . Fine Job
an issue i came across is when using nginx as a front for live server. nginx conf file is set to redirect all the /javascripts/ request to the public/javascripts folder.
this means the call to the dynamic files will never return the correct file.
What can we do in this case?
thank you very nice plugin
thnak you very best in formation
Internet Explorer needs var added to new variables to avoid the 'Object or method not found'
// javascripts/dynamic_states.js.erb
var states = new Array();
<% for state in @states -%>
states.push(new Array(<%= state.country_id %>, '<%=h state.name %>', <%= state.id %>));
<% end -%>
function countrySelected() {
var country_id = $('person_country_id').getValue();
var options = $('person_state_id').options;
options.length = 1;
states.each(function(state) {
if (state[0] == country_id) {
options[options.length] = new Option(state[1], state[2]);
}
});
if (options.length == 1) {
$('state_field').hide();
} else {
$('state_field').show();
}
}
document.observe('dom:loaded', function() {
countrySelected();
$('person_country_id').observe('change', countrySelected);
});
I tried it and now it works fine...
I have this running fine. However, it seems that the javascript is either running before the controller has finished running, or the javascript is not able to use variables form the controller
Any thoughts on this one?
Michael
Hi everyone,
I've implemented a plugin called dependent_select on
http://github.com/splendeo/dependent_select/tree/master
The syntax is very similar to collection_select - you just add another method for "filtering".
<%= f.dependent_collection_select :state_id, State.find(:all), :id, :name, :country_id, :prompt => "Select a State" %>
This will generate all the needed javascript - with the exception of the main function, that should be included on the layout.
Note that the current implementation downloads everything at the begining on a big javascript array; if you are looking for an AJAX solution you'll have to look elsewhere - for now :) at least.
Regards!
code is very nice
não entendi
thank you
hey Ryan
there's been a lot of feedback here
1) care to respond to some of them at least?
2) a non-fully client side approach is to use Ajax. Could you please do a railscast on how to achieve the same effect using ajax?
One thing is not clear to me. Is the action dynamic_states expected to be called manually everytime the contries/states get changed? If not, how does it get invoked? In the tutorial, Ryan invoked the method directly using the URL. If that is not done, is this still going to work?
thank. your article is succesful
thanks for this cast, Ryan, it made my day a few weeks ago.
How would you do this with Ajax, though?
very nice
great tutorial. thanks a lot mate.
took me a week to make this work but still a great code
Checkout my solution that neads no JavaScript code writing, and requires fever lines of code: http://programmers-blog.com/2009/11/12/dependant-dropdowns-select-menus-using-rails
nice job!
thank you for the great help and greetings from me
Very good article guys!
Anyone have any experience doing dynamic selects menus with very large numbers of option data? I've tried just JS and Ajax and both options are very slow on the first change. My first select has about 700 options, the second over 5000.
Thanks for this tutorial. I've been looking for some time for a decent one on dynamic select menus. You'd be surprised how much trash info there is out there.<a href="http://oynetwork.com/">lead</a>
thank you for the great help and greetings from me
thnak Sie besten in Bildung
Moin moin! Wirklich schöne Seite die ihr da habt.Bin schon ein paar mal auf eurer Seite gewesen und jetzt hab ich mir gedacht, ich schreib euch mal was nettes ins Gästebuch. Also echt toll was ihr hier gemacht habt. Macht weiter so. Ich würde ich mich über einen Gegenbesuch auf meiner Webseite "Urlaub auf Sylt oder an der Ostsee" sehr freuen.
i´m not so familiar with using java scripts but still learning. Try to work with this one Thx.
Great railscast, as always!
I've implemented all the code, but the dynamic menu isn't working - no errors are thrown, but the first selection list has no impact on the second selection list (and the second one isn't even hidden, either).
Is there something different about Rails 2.3.5 that I should consider??
Thanks!
I figured it out - I needed to implicitly map.resources :javascripts and remove the map.connect line.
Thanks - works like a charm now!
This episode was great!
This description really helped me a lot. Thanks
I think I'm in love with Ryan. ;)
But I have a question for anyone... I implemented the dynamic select menus just fine. But I want my final select to populate a "description" field that is not editable. Anyone know how to do that?
Thanks!
How would I do this sort of thing, only NOT as a SELECT?
For instance, I have a request form - the user selects from Categories (Hardware, Software, Media, etc)
Based on that selection, the next select box is populated with its corresponding Products (PC, Monitor, Printer, etc)
Based on that selection, I want the product.description to display below the selected product.
HELP!??!? and THANK YOU! :)
great article my friend
Thank you very interesting html-codes. well done my friend
Old thread but it was helpful for me. thanx
thank yo0u very much backlink için dostum :)
thank yo0u very much backlink için dostum :)
thank you very much bebeğem :D
Is there a place where i could find and download the full source code for this tutorial?
Thx!
I implemented this, and all works fine...except my select list is not ordered alphabetically. Any ideas?
Thanks!
I'm trying to implement this on an edit page (rather than a new page) and in my application I have Buildings and Rooms instead of Countries and States, but the relationship is basically the same.
It is not working for me. Regardless of which Building (country) I select, the list of Rooms (states) does not change. I have no idea what the problem is.
Taking out "countrySelected();" in the amended javascript makes this work for my app on rails 2.0.2.
I would like to filter the states list by the pre-selected country though. What might I be missing?
Hi. This was a great help. Thanks for that. Just one little problem that I am facing. The second drop down list that is displayed, is not sorted. I want to sort it alphabetically. Right now, it sorts it by id. Any ideas?
Thanks.
doesn't work, i have rails 3. javascript file doesn't load.
i think the dom:loaded doesn't work, but i don't know, i'm new in rails, can anybody help me?
doesn't work with 11720 records, why?
how to dynamic update another selector when a selector changes by ajax on ruby?
because there are not load all select info when page loaded, should call server to get another select reload when a selector changes.
e.g I used country_select and state_select plugins. I don't know how to make state_select dynamic update after country_select changes.
I would like to see this Railscast updated for Rails 3.1...
it will be nice to have an update for this Railscast with Rails 3.1 and large volume of records.
hi Ryan, I have done the same thing i.e dynamic select menus but using jquery. Please have a look here
http://rubylogix.blogspot.com/2011/08/dynamic-select-menus-in-rails-3.html
and you can find it on git-hub.
https://github.com/sandeepleo11/Dynamic-Select-Menus-in-Rails-3.
can u make a video of this. so that i would be happy.
Your Github link does not work.
sorry Dom
period at the last has gone out the link.
plz consider period at the last.
Thank You.
nice piece of app. I finally get it right. Thanks, I've been looking for this for a month already.
Mac Martine - can you elaborate on how you got this working for rails 3? I have everything loaded with no errors but the javascript doesn't seem to run.
Thanks!
Ryan - first of all thanks a lot for doing this episode. But I'm having a few problems implementing this.
Ryan - first of all thanks a lot for doing this episode. But I'm having a few problems implementing this.
Thanks a lot for doing this episode.
I'm having a few problems implementing this.
Can you elaborate on how you got this working for rails 3?
Thanks!!
Do some one was do it the same example with jQuery???
Guys can some one help me, I found this error:
TypeError: Object 1,our first hello world,1,1,hola,1 has no method 'each'
That error was on the 8 line of my js.erb file
var lectures = new Array();
<% for lecture in @lectures -%>
lectures.push(new Array(<%= lecture.course_id %>, '<%=h lecture.title %>', <%= lecture.id %>));
<% end -%>
function courseSelected() {
course_id = $('#course_id').val();
options = $('#lecture_id').find("option");
options.length = 1;
lectures.each(function(lecture) {
if (lecture[0] == course_id) {
options[options.length] = new Option(lecture[1], lecture[2]);
}
});
if (options.length == 1) {
$('#lecture_field').hide();
} else {
$('#lecture_field').show();
}
}
$(document).ready(function() {
$('#lecture_field').hide();
$('#course_id').live('change', courseSelected);
});
I got some probems with my .js file can you please explain it on rails 3.2
I have a problem in using the dynamic select menu along with nested attributes. please help me . I have posted my question in http://stackoverflow.com/questions/17546917/how-to-include-both-dynamic-select-menu-and-nested-attributes-together-in-rails
Link
These drop down menus are really often used these days.. A lot of websites do use them. Rail seems to be a management system like drupal.
A cool slide menu is used at this site here http://www.nitis-flotte-kindermoden.de Its uses another system (a shopping system) from cosmoshop.
But I think all systems are based of Javascript?!
How I can do this for Active Admin??