How do I create an interactive form with Simple Form? - ruby-on-rails

I have a model (Listing) that has many, many attributes (say 25).
I would like to create an AJAX form that is dynamic based on the input in the form.
Meaning that if a user chooses type=b, they will see other fields that they should see and not ones they shouldn't.
Ideally they should load immediately, with the right content from the db - i.e. in an AJAXy way.
What's the best way to approach this?
Thanks.
Edit: Here is an example of my _form.html.erb. You will notice that I have included 2 if statements that indicate which fields should show if the property_type value chosen is one of those specified:
<%= simple_form_for(#listing) do |f| %>
<%= f.error_notification %>
<div class="form-inputs">
<%= f.input :headline %>
<%= f.input :price %>
<%= f.association :property_type %>
If property_type == "coop"
<%= f.input :maintenance %>
<%= f.input :coop_deductible %>
<%= f.input :flip_tax %>
if property_type == "condo"
<%= f.input :common_charges %>
<%= f.input :taxes %>
</div>
<div class="form-actions">
<%= f.button :submit %>
</div>
<% end %>
Edit 2:
This is the Rails form helper that I used - powered by the gem Simple_Form:
<%= simple_form_for #listing, :defaults => { :wrapper_html => { :class => 'form-horizontal' } } do |f| %>
<%= f.error_notification %>
<fieldset>
<%= f.association :listing_category, :label => "Category: ", :label_html => { :class => "control-label"}, :wrapper_html => { :class => "controls"} %>
<div style="display: none;" data-show-for="Exclusive">
<%= f.association :listing_type %>
<%= f.association :user %>
<%= f.association :boro %>
</div>
<div style="display: none;" data-show-for="Open">
<%= f.association :neighborhood %>
<%= f.association :building %>
<%= f.association :term %>
<%= f.association :property_type %>
</div>
<div class="form-actions">
<%= f.button :submit, :class => "btn btn-primary" %>
<!-- <button type="submit" class="btn btn-primary">Save and Continue</button>
<button type="reset" class="btn">Cancel</button> -->
</div>
</fieldset>
<% end %>
This is the HTML it produced:
<form accept-charset="UTF-8" action="/listings" class="simple_form new_listing" id="new_listing" method="post" novalidate="novalidate"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="1oDfg41Wx/SiPCsvf4qTAcxhFUGSNlhlLfkMy8nHW1E=" /></div>
<fieldset>
<div class="control-group select optional controls"><label class="select optional control-label control-label" for="listing_listing_category_id">Category:</label><div class="controls"><select class="select optional" id="listing_listing_category_id" name="listing[listing_category_id]"><option value=""></option>
<option value="1">Exclusive</option>
<option value="2">Open</option></select></div></div>
<div style="display: none;" data-show-for="Exclusive">
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_listing_type_id">Listing type</label><div class="controls"><select class="select optional" id="listing_listing_type_id" name="listing[listing_type_id]"><option value=""></option>
</select></div></div>
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_user_id">User</label><div class="controls"><select class="select optional" id="listing_user_id" name="listing[user_id]"><option value=""></option>
<option value="1">First User</option>
<option value="2">Second User</option>
<option value="3">Third User</option>
<option value="4">Fourth User</option>
<option value="5">Fifth User</option></select></div></div>
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_boro_id">Boro</label><div class="controls"><select class="select optional" id="listing_boro_id" name="listing[boro_id]"><option value=""></option>
<option value="1">Brooklyn</option></select></div></div>
</div>
<div style="display: none;" data-show-for="Open">
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_neighborhood_id">Neighborhood</label><div class="controls"><select class="select optional" id="listing_neighborhood_id" name="listing[neighborhood_id]"><option value=""></option>
<option value="1">Prospect Heights</option></select></div></div>
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_building_id">Building</label><div class="controls"><select class="select optional" id="listing_building_id" name="listing[building_id]"><option value=""></option>
<option value="1">Trump Towers</option></select></div></div>
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_term_id">Term</label><div class="controls"><select class="select optional" id="listing_term_id" name="listing[term_id]"><option value=""></option>
</select></div></div>
<div class="control-group select optional form-horizontal"><label class="select optional control-label" for="listing_property_type_id">Property type</label><div class="controls"><select class="select optional" id="listing_property_type_id" name="listing[property_type_id]"><option value=""></option>
<option value="1">Coop</option></select></div></div>
</div>
<div class="form-actions">
<input class="btn btn btn-primary" name="commit" type="submit" value="Create Listing" />
<!-- <button type="submit" class="btn btn-primary">Save and Continue</button>
<button type="reset" class="btn">Cancel</button> -->
</div>
</fieldset>
</form>
This is the JS that I included in my listing.js - which corresponds to the file that this form is on app/views/listings/new.html.erb
$(document).ready(function({
$('#listing_listing_category_id').on('change', function(){
var option = $(this).find(':selected');
$('[data-show-for]').hide(); //And maybe reset?
$('[data-show-for="+ option.text +"]').show()
});
});
When I chose the option I want, it doesn't show me the fields I want to see.

Personally I wouldn't use AJAX, just straight JS/JQuery to show/hide on click using data attributes.
See fiddle: http://jsfiddle.net/XnPZF/
First, add the data attributes to the sections you want to hide/show:
<div style="display: none;" data-show-for="coop">
<%= f.input :maintenance %>
<%= f.input :coop_deductible %>
<%= f.input :flip_tax %>
</div>
<div style="display: none;" data-show-for="condo">
<%= f.input :common_charges %>
<%= f.input :taxes %>
</div>
Then create a change event on the select:
$('#listing_property_type').on('change', function(){
var option = $(this).find(':selected');
$('[data-show-for]').hide(); //And maybe reset?
$('[data-show-for='+ option.text() +']').show()
});
For data-show-for, you can use Option text or value, just be sure to make sure the event knows which. If you plan to use this a lot of times, you could generalize it, but that would mean building your options.

Related

Display error message on invalid special field

I would know how display a error message on my invalid field
I have a simple form
<%= simple_form_for #bien do |f| %>
<div class="col-md-6 col-md-offset-3 text-center">
<div class="row">
<div class="form-group">
<%= f.input :adress, :input_html =>{:id => 'address'}, placeholder: 'Adresse', label: "Adresse" %>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12 text-center">
<div class="form-group">
<h5><b>Type de mandat</b></h5>
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-danger active" style="margin-right: 10px;">
<input id="bien_mandat_type_true" name="bien[mandat_type]" type="radio" autocomplete="off" value="Simple"/> Simple
</label>
<label class="btn btn-danger" style="margin-right: 10px;">
<input id="bien_mandat_type_true" name="bien[mandat_type]" type="radio" autocomplete="off" value="Exclusif" /> Exclusif
</label>
<label class="btn btn-danger">
<input id="bien_mandat_type_true" name="bien[mandat_type]" type="radio" autocomplete="off" value="Délégation" /> Délégation
</label>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-12 text-center">
<%= f.button :submit, "Valider", class: "btn btn-fill callpremium btn-danger btn-lg" %>
</div>
<% end %>
And i would display a error message when my input is empty like i do with the normal adress field, i wont use flash messages
Simple form error messages are driven by your model's validations. Add a presence validation to the fields you want to have errors when empty and simple form will respond accordingly automatically. For example, you could add this to your model to give an error when address is empty:
validates :address, presence: true

Checkboxes in horizontal form, and on the right side of the label

Is it possible to have the checkbox labels on the left like the others, and the checkbox on the right like the other inputs with a horizontal form?
My current setup
It looks pretty awful.
EDIT:
<%= simple_form_for :apartment, :html => {:multipart => true, :class => 'form-horizontal'}, wrapper: :horizontal_form do |f| %>
<%= f.input :pets, as: :boolean, label: 'Husdyr tilladt' %>
<% end %>
which generates the following html in the view:
<div class="form-group boolean optional apartment_pets">
<div class="checkbox"><input value="0" type="hidden" name="apartment[pets]">
<label class="boolean optional" for="apartment_pets"><input class="boolean optional" type="checkbox" value="1" name="apartment[pets]" id="apartment_pets">
Husdyr tilladt
</label>
</div>
</div>
You can add pull-right to the class of your checkbox element like so:
<input name="uh" id="uhhuh" type="checkbox" class="pull-right" />
Updated answer with user provided code:
<div class="form-group boolean optional apartment_pets">
<div class="checkbox"><input value="0" type="hidden" name="apartment[pets]">
<label class="boolean optional" for="apartment_pets">Husdyr tilladt</label>
<input class="boolean optional" type="checkbox" value="1" name="apartment[pets]" id="apartment_pets" class="pull-right">
</div>
</div>
I never used simple_form but from browsing the documentation, it looks like you should use a combination of :label => false and :inline_label => true to position your label.

Rail 4: Conditionals in a Scaffold

I am still learning RoR but I cant learn by following someone else's code. I have decided to implement by own app.
I have generated a scaffold and in the _form.html.erb I have this:
<div class="field">
<%= f.label :bath_accessories %><br>
<%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %><br>
</div>
When the user selects "Shower" from the above lists, I want to enable in view:
<div class="field">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
I am lost where to put the if statement for: <%= f.select :bath_accessories, options_for_select(["Shower", "Extractor Fan", "Lights", "Shaver", "Heat Rail"]) %> But I did this and nothing shows:
<% if :bath_accessories[0] %>
# What to out put here with "<%= code %>?
Generated HTML Tag:
<form class="new_bathroom_accessory" id="new_bathroom_accessory" action="/bathroom_accessories" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="✓" /><input type="hidden" name="authenticity_token" value="r9M+Q7Np+/i68gwj65JSvV8wi4+4yb5d6tFWBHMw8k9nz1oRHGzh7AZHOTFvlaiS2lmqTch356vVYNlh7Urifw==" />
<div class="field">
<label for="bathroom_accessory_bath_accessories">Bath accessories</label><br>
<select name="bathroom_accessory[bath_accessories]" id="bathroom_accessory_bath_accessories"><option value="Shower">Shower</option>
<option value="Extractor Fan">Extractor Fan</option>
<option value="Lights">Lights</option>
<option value="Shaver">Shaver</option>
<option value="Heat Rail">Heat Rail</option></select><br>
</div>
<div class="field">
<label for="bathroom_accessory_watts">Watts</label><br>
<input type="number" name="bathroom_accessory[watts]" id="bathroom_accessory_watts" />
</div>
<div class="field">
<label for="bathroom_accessory_volts">Volts</label><br>
<input type="number" name="bathroom_accessory[volts]" id="bathroom_accessory_volts" />
</div>
<div class="actions">
<input type="submit" name="commit" value="Create Bathroom accessory" />
</div>
</form>
By adding an id to particular <div>,you can control that <div> as per user selection.
<div class="field" id="shower_id">
<%= f.label :watts %><br>
<%= f.number_field :watts %>
</div>
And you need JavaScript or JQuery code like this
$('#bathroom_accessory_bath_accessories').on('change',function(){
if( $(this).val()==="Shower"){
$("#shower_id").show()
}
else{
$("#shower_id").hide()
}
});
DEMO

Rails form_for html being set to display: none

I have a standard rails form_for tag for creating and editing a new hotel. This renders just fine when visited via the edit_hotels_path, however when visting the new_hotels_path the html form tag is being set to display: none; causing the form to not show only in the "new" view.
I have restarted the server, emptied the cache, made sure they are using the same CSS but it still renders with display set to none.
Here are the styles as seen using developer tools
<form accept-charset="UTF-8" action="/hotels" class="new_hotel" id="new_hotel" method="post" style="display: none; "><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓"><input name="authenticity_token" type="hidden" value="pDlR3gV2tm+Z7xRFdC0uclNY13FlzxUSOjOrHs2ttO0="></div>
element.style {
display: none;
}
below is the html source being rendered, which doesn't include display: none;
<form accept-charset="UTF-8" action="/hotels" class="new_hotel" id="new_hotel" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="pDlR3gV2tm+Z7xRFdC0uclNY13FlzxUSOjOrHs2ttO0=" /></div>
<div class="control-group">
<div class="controls">
<input id="hotel_name" name="hotel[name]" placeholder="Name..." size="30" type="text" /><br>
<select id="hotel_year" name="hotel[year]"><option value="2012">2012</option>
<option value="2013">2013</option>
<option value="2014">2014</option>
<option value="2015">2015</option></select><br>
<select id="hotel_month" name="hotel[month]"><option value="January">January</option>
<option value="February">February</option>
<option value="March">March</option>
<option value="April">April</option>
<option value="May">May</option>
<option value="June">June</option>
<option value="July">July</option>
<option value="August">August</option>
<option value="September">September</option>
<option value="October">October</option>
<option value="November">November</option>
<option value="December">December</option></select><br>
<textarea cols="40" id="hotel_body" name="hotel[body]" placeholder="Hotel info up to 1000 words..." rows="20">
</textarea><br>
<input id="hotel_meta_tags" name="hotel[meta_tags]" placeholder="Enter meta tags for image, as a comma separated list..." size="30" type="text" /><br>
<legend>Winner</legend>
<input name="hotel[winner]" type="hidden" value="0" /><input id="hotel_winner" name="hotel[winner]" type="checkbox" value="1" />
<br/>
</div>
<div class="form-actions">
<input class="btn-large btn-success" name="commit" type="submit" value="create" />
</div>
</div>
</form>
below is the code, would appreciated any help.
_form.html.erb
<%= form_for #hotel do |f| %>
<% if #hotel.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#hotel.errors.count, "error") %> prohibited this article from being saved:</h2>
<ul>
<% #hotel.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render partial: "shared/code_sheet" %>
<div class="control-group">
<div class="controls">
<%= f.text_field :name, placeholder: "Name..." %><br>
<%= f.select :year, [2012, 2013, 2014, 2015] %><br>
<%= f.select :month, ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] %><br>
<%= f.text_area :body, placeholder: "Hotel info up to 1000 words..." %><br>
<%= f.text_field :meta_tags, placeholder: "Enter meta tags for image, as a comma separated list..." %><br>
<legend>Winner</legend>
<%= f.check_box :winner %>
<br/>
</div>
<div class="form-actions">
<%= f.submit "create", class: "btn-large btn-success" %>
</div>
</div>
<% end %>
edit.html.erb
<div class="container">
<h1>Editing hotel</h1>
<%= render "form" %>
<%= link_to 'hotels index', hotels_path %>
</div>
new.html.erb
<div class="container">
<h1>New hotel</h1>
<%= render "form" %>
<%= link_to 'hotels index', hotels_path %>
</div>
It could be anything. You must know what is in your CSS. Did you search for 'display: none;' in your CSS files and checked the matches? element.style is usually set directly on the HTML tag. Search the view also place debugging string to make sure it is pulling the appropriate .html.

Why isn't my signup form working until all of the form fields are filled?

A few days ago, my signup form for an app I'm building was working fine. The 'create my account' button would work even if no form fields were filled, and an error message would be displayed right away. Now, when I try to submit the form, the form only will submit or show error messages when all of the fields have been filled. If I try to submit the form without filling all of the fields, nothing happens. The signup button doesn't work correctly.
The only significant change that I made that I can think of is switching the stripe plan I was using to a free trial plan instead of a plan where the purchaser of the application pays up-front. I have no idea what could be causing this problem, so I don't know what code I should post. Any help you can provide would be appreciated.
The signup form I have in rails is as follows(minus some javascript that I'm using for Stripe):
<div class="row">
<div class="span6 offset4">
<%= form_for(#user) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Password confirmation" %>
<%= f.password_field :password_confirmation %>
<%= f.label :morning_meds, "Do you take medications in the morning?" %>
<%= f.select :morning_meds, [['Yes'], ['No']] %>
<%= f.label :lunch_meds, "Do you take medications at lunch?" %>
<%= f.select :lunch_meds, [['Yes'], ['No']] %>
<%= f.label :night_meds, "Do you take medications in the evening?" %>
<%= f.select :night_meds, [['Yes'], ['No']] %>
<%= f.label :time_zone, "Choose your time zone" %>
<%= f.select :time_zone, [['Eastern'], ['Central'], ['Mountain'], ['Pacific']] %>
<%= f.label :phone_number, "Your cell phone number" %>
<%= f.text_field :phone_number %>
<div class="form-row">
<label>Card Number</label>
<input type="text" size="20" autocomplete="off" class="card-number" />
</div>
<div class="form-row">
<label>CVC</label>
<input type="text" size="4" autocomplete="off" class="card-cvc" />
</div>
<div class="form-row">
<label>Expiration Date</label>
<%= select_month nil, {add_month_numbers: true}, {name: nil, class: 'card-expiry-month' } %>
<span> / </span>
<%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, class: 'card-expiry-year' } %>
</div>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
<div class="row">
<div class="span6 offset4">
<form accept-charset="UTF-8" action="/users" class="new_user" id="new_user" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="QqrFVykfeY1+9jImvp8VjTzrQxq8VlBF+vC6V85klw0=" /></div>
<label for="user_name">Name</label>
<input id="user_name" name="user[name]" size="30" type="text" />
<label for="user_email">Email</label>
<input id="user_email" name="user[email]" size="30" type="text" />
<label for="user_password">Password</label>
<input id="user_password" name="user[password]" size="30" type="password" />
<label for="user_password_confirmation">Password confirmation</label>
<input id="user_password_confirmation" name="user[password_confirmation]" size="30" type="password" />
<label for="user_morning_meds">Do you take medications in the morning?</label>
<select id="user_morning_meds" name="user[morning_meds]"><option value="Yes">Yes</option>
<option value="No">No</option></select>
<label for="user_lunch_meds">Do you take medications at lunch?</label>
<select id="user_lunch_meds" name="user[lunch_meds]"><option value="Yes">Yes</option>
<option value="No">No</option></select>
<label for="user_night_meds">Do you take medications in the evening?</label>
<select id="user_night_meds" name="user[night_meds]"><option value="Yes">Yes</option>
<option value="No">No</option></select>
<label for="user_time_zone">Choose your time zone</label>
<select id="user_time_zone" name="user[time_zone]"><option value="Eastern">Eastern</option>
<option value="Central">Central</option>
<option value="Mountain">Mountain</option>
<option value="Pacific">Pacific</option></select>
<label for="user_phone_number">Your cell phone number</label>
<input id="user_phone_number" name="user[phone_number]" size="30" type="text" />
<div class="form-row">
<label>Card Number</label>
<input type="text" size="20" autocomplete="off" class="card-number" />
</div>
<div class="form-row">
<label>CVC</label>
<input type="text" size="4" autocomplete="off" class="card-cvc" />
</div>
<div class="form-row">
<label>Expiration Date</label>
<select class="card-expiry-month" id="date_month">
<option value="1">1 - January</option>
<option value="2">2 - February</option>
<option value="3">3 - March</option>
<option value="4">4 - April</option>
<option value="5">5 - May</option>
<option value="6">6 - June</option>
<option value="7">7 - July</option>
<option value="8">8 - August</option>
<option value="9">9 - September</option>
<option value="10">10 - October</option>
<option value="11">11 - November</option>
<option value="12">12 - December</option>
</select>
<span> / </span>
<select class="card-expiry-year" id="date_year">
<option value="2012">2012</option>
<option value="2013">2013</option>
<option value="2014">2014</option>
<option value="2015">2015</option>
<option value="2016">2016</option>
<option value="2017">2017</option>
<option value="2018">2018</option>
<option value="2019">2019</option>
<option value="2020">2020</option>
<option value="2021">2021</option>
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
<option value="2025">2025</option>
<option value="2026">2026</option>
<option value="2027">2027</option>
</select>
</div>
<input class="btn btn-large btn-primary" name="commit" type="submit" value="Create my account" />
</form>
It'd be helpful to see the HTML source your view generates, but you likely have 1+ fields with the HTML5 required attribute that you are leaving blank.
By default, newer browsers like Chrome will not allow the form to submit until all fields flagged with the required attribute have a value. To stop this you can add the novalidate attribute to the <form ... tag.
<%= form_for(#user, { :novalidate => true }) do |f| %>

Resources