Thibaud Clement Thibaud Clement - 6 months ago 56
jQuery Question

Rails 4 form: conditional display of fields based on radio button selection

First, please excuse me if this question is dumb, I am just starting to wrap my head around Rails, and Javascript & jQuery are a whole new world for me.

I have found the following, similar questions, but simply don't understand how they could apply to my situation:



That being said, here is my question.

In my Rails 4 app, I have the following Rails form (I am NOT using Simple Form):

<div class="calendar_details">
<%= f.label :target_relationship %>
<%= radio_button_tag(:target_relationship, "B2C", :checked => true, :onclick=>"showMe('calendar_details_b2c')", {:class => "radio_button_target_relationship_b2C"}) %>
<%= label_tag(:target_relationship, "B2C") %>
<%= radio_button_tag(:target_relationship, "B2B", :onclick=>"showMe('calendar_details_b2b')", {:class => "radio_button_target_relationship_b2b"}) %>
<%= label_tag(:target_relationship, "B2B") %>
</div>

<div class="calendar_details">
<%= f.label :target_country %><%= f.country_select :target_country, ["United States"] %>
</div>

<div id="calendar_details_b2c">

<div class="calendar_details">
<%= f.label :target_gender %><%= radio_button_tag(:target_gender, "Female") %><%= label_tag(:target_relationship, "Female") %><%= radio_button_tag(:target_gender, "Male") %><%= label_tag(:target_relationship, "Male") %><%= radio_button_tag(:target_gender, "Both", :checked => true) %><%= label_tag(:target_relationship, "Both") %>
</div>
<div class="calendar_details">
<%= f.label :target_age_lower_limit %><%= f.select :target_age_lower_limit, (0..99) %>
</div>
<div class="calendar_details">
<%= f.label :target_age_upper_limit %><%= f.select :target_age_upper_limit, (0..99) %>
</div>
<div class="calendar_details">
<%= f.label :target_household_income_lower_limit %><%= f.select :target_household_income_lower_limit, ['Less than $10,000', '$10,000', '$20,000', '$30,000', '$40,000', '$50,000', '$60,000', '$70,000', '$80,000', '$90,000', '$100,000', '$110,000', '$120,000', '$130,000', '$140,000', '$150,000', '$160,000', '$170,000', '$180,000', '$190,000', '$190,000', '$200,000', 'More than $200,000'] %>
</div>
<div class="calendar_details">
<%= f.label :target_household_income_upper_limit %><%= f.select :target_household_income_upper_limit, ['Less than $10,000', '$10,000', '$20,000', '$30,000', '$40,000', '$50,000', '$60,000', '$70,000', '$80,000', '$90,000', '$100,000', '$110,000', '$120,000', '$130,000', '$140,000', '$150,000', '$160,000', '$170,000', '$180,000', '$190,000', '$190,000', '$200,000', 'More than $200,000'] %>
</div>

</div>

<div id="calendar_details_b2b">

<div class="calendar_details">
<%= f.label :target_company_size %><%= f.select :target_company_size, ['Self-employed', '1-10 employees', '11-50 employees', '51-200 employees', '201-500 employees', '501-1,000 employees', '1,001-5,000 employees', '5,001-10,000 employees', 'More than 10,000 employees'] %>
</div>
<div class="calendar_details">
<%= f.label :target_industry %><%= f.select :target_industry, ['Art & Entertainment', 'Autos & Vehicles', 'Beauty & Fitness', 'Books & Litterature', 'Business & Industrial', 'Computer & Electronics', 'Finance', 'Food & Drinks', 'Games', 'Hobbies & Leisure', 'Home & Garden', 'Internet & Telecom', 'Jobs & Education', 'Law & Government', 'News', 'Online Communities', 'People & Society', 'Pets & Animals', 'Real Estate', 'Science', 'Shopping', 'Sports', 'Travel'] %>
</div>

</div>


Based on what users check on the first radio button (either "B2C" or "B2B"), I would like to either display the
calendar_details_b2c
div
, or the
calendar_details_b2b
div
.

I understand I am going to need to hide both
div
s, then to implement some form of condition, checking which radio button is checked, and finally display the right
div
.

As you can see, I tried to add an
onclick
option and some specific classes to my radio buttons, but then I am stuck: I don't know how to build the correct js function, and I don't know where to include it (in the
.html.erb
file of the form, in the header of the app, in the
application.js
file?).

—————

UPDATE: as per Ziv Galili's answer, here is what I have now:

In
app/assets/javascript/custom/calendars.js
:

$(document).ready(function() {
$('input[type=radio][name=calendar').change(function () {
// first: hide all the divs
$('#calendar_details_b2c').css("display","none");
$('#calendar_details_b2b').css("display","none");

// then get the div ID to show (I stored it in the "value" of the radio button)
var fieldToShow = $(this).val();
// now use jQuery selector and change the display setting of that field
$("#" + fieldToShow).css("display","block");
});
});


In
application.js
, I added
//= require_tree ./custom
to take the above code into consideration in my app.

In the view where my form is (
Calendars#New
view), I now have:

<div class="calendar_details">
<%= f.label :target_relationship, "Business relationship" %>
<%= f.radio_button :target_relationship, "calendar_details_b2c", :checked => true %>
<%= f.label(:target_relationship, "B2C") %>
<%= f.radio_button :target_relationship, "calendar_details_b2b", :checked => false %>
<%= f.label(:target_relationship, "B2B") %>
</div>

<div class="calendar_details">
<%= f.label :target_country, "Country" %><%= f.country_select :target_country, ["United States"] %>
</div>

<div id="calendar_details_b2c">

<div class="calendar_details">
<%= f.label :target_gender, "Gender" %><%= radio_button_tag(:target_gender, "Female") %><%= label_tag(:target_relationship, "Female") %><%= radio_button_tag(:target_gender, "Male") %><%= label_tag(:target_relationship, "Male") %><%= radio_button_tag(:target_gender, "Both", :checked => true) %><%= label_tag(:target_relationship, "Both") %>
</div>
<div class="calendar_details">
<%= f.label :target_age_lower_limit, "Age / Lower limit" %><%= f.select :target_age_lower_limit, (0..99) %>
</div>
<div class="calendar_details">
<%= f.label :target_age_upper_limit, "Age / Upper limit" %><%= f.select :target_age_upper_limit, (0..99) %>
</div>
<div class="calendar_details">
<%= f.label :target_household_income_lower_limit, "Household income / Lower limit" %><%= f.select :target_household_income_lower_limit, ['Less than $10,000', '$10,000', '$20,000', '$30,000', '$40,000', '$50,000', '$60,000', '$70,000', '$80,000', '$90,000', '$100,000', '$110,000', '$120,000', '$130,000', '$140,000', '$150,000', '$160,000', '$170,000', '$180,000', '$190,000', '$190,000', '$200,000', 'More than $200,000'] %>
</div>
<div class="calendar_details">
<%= f.label :target_household_income_upper_limit, "Household income / Upper limit" %><%= f.select :target_household_income_upper_limit, ['Less than $10,000', '$10,000', '$20,000', '$30,000', '$40,000', '$50,000', '$60,000', '$70,000', '$80,000', '$90,000', '$100,000', '$110,000', '$120,000', '$130,000', '$140,000', '$150,000', '$160,000', '$170,000', '$180,000', '$190,000', '$190,000', '$200,000', 'More than $200,000'] %>
</div>

</div>

<div id="calendar_details_b2b">

<div class="calendar_details">
<%= f.label :target_company_size, "Company size" %><%= f.select :target_company_size, ['Self-employed', '1-10 employees', '11-50 employees', '51-200 employees', '201-500 employees', '501-1,000 employees', '1,001-5,000 employees', '5,001-10,000 employees', 'More than 10,000 employees'] %>
</div>
<div class="calendar_details">
<%= f.label :target_industry, "Industry" %><%= f.select :target_industry, ['Art & Entertainment', 'Autos & Vehicles', 'Beauty & Fitness', 'Books & Litterature', 'Business & Industrial', 'Computer & Electronics', 'Finance', 'Food & Drinks', 'Games', 'Hobbies & Leisure', 'Home & Garden', 'Internet & Telecom', 'Jobs & Education', 'Law & Government', 'News', 'Online Communities', 'People & Society', 'Pets & Animals', 'Real Estate', 'Science', 'Shopping', 'Sports', 'Travel'] %>
</div>

</div>


However, I can't seem to make this work: when I visit the
Calendars#New
view, I do see the radio buttons to select either B2C or B2B, but whichever button I select, nothing is displayed below (neither the B2C section nor the B2B section).

What am I missing?

—————

UPDATE 2: So, I updated my code as Ziv Galili's new comment, ie: paying attention to the name of the button group, which is actually
calendar[target_relationship]
.

When I did that, and tried to go to my view, I got a
execJS::RuntimeError
, which made me realize we were using pure JavaScript, while my Rails app seems to be using CoffeeScript.

So, I deleted
app/assets/javascript/custom/calendars.js
, converted Ziv Galili's code to CoffeeScript and added it to app/assets/javascript/calendars.coffee:

$('input[type=radio][name=calendar[target_relationship]]').change ->
# first: hide all the divs
$('#calendar_details_b2c').css 'display', 'none'
$('#calendar_details_b2b').css 'display', 'none'
# then get the div ID to show (i stored it in the "value" of the radio button
fieldToShow = $(this).val()
# now use jQuery selector and change the display setting of that field
$('#' + fieldToShow).css 'display', 'block'
return


I also replaced
//= require_tree ./custom
with
//= require_tree .
to make sure all my
.coffee
files were loaded through
application.js
.

Despite all these code updates, I still do not get the result I am expecting: none of the
div
s are displayed in my views:

enter image description here

I must be missing something really, really obvious, but I can't figure out what it is.

Any idea?

—————

Any kind of help would be highly appreciated.

Answer

i would do something like this:

jsFiddle

Explanation:

lets say the HTML will be:

<form action="">
  <input type="radio" name="calendars" value="calendar_details_b2b">B2B
  <br>
  <input type="radio" name="calendars" value="calendar_details_b2c">B2C
</form>
<div id="calendar_details_b2c" style=>
  content of B2C
</div>
<div id="calendar_details_b2b">
  content of B2B
</div>

add css code so the divs won't be shown on page load:

#calendar_details_b2c,
#calendar_details_b2b
{
  display: none;
}

JS code will be:

$('input[type=radio][name=calendars]').change(function () {
  // first: hide all the divs
  $('#calendar_details_b2c').css("display","none");
  $('#calendar_details_b2b').css("display","none");

  // then get the div ID to show (i stored it in the "value" of the radio button
  var fieldToShow = $(this).val();
  // now use jQuery selector and change the display setting of that field
  $("#" + fieldToShow).css("display","block");
});

UPDATE:

as for your update, please pay attention that in the JS section the name of the button group match their name in the HTML file:

js:

$('input[type=radio][name=NAME_OF_BUTTON_GROUP]')

to find the name in the HTML you can (in chrome):

  1. Right click on one of the radio buttons
  2. press Inspect Element
  3. in the element inspector look for the name attribute of the input

<input checked="checked" id="something_calendar_details_b2c" name="THIS IS THE NAME" type="radio" value="calendar_details_b2c">

NOTE: if you have square brackets in the name (or any other special character) you should wrap it with apostrophes

$('input[type=radio][name="calendar[target_relationship]"]')