I am able with the radio button and a little javascript to toggle between the two categories, but even if one category is hidden it's data still sends.
challenge.rb
class Challenge < ActiveRecord::Base
scope :oneshot, -> { where(categories: 'One-Shot') }
scope :ongoing, -> { where(categories: 'Ongoing') }
_form
<%= form_for(#challenge) do |f| %>
<%= f.text_field :action %>
<% Challenge::CATEGORY.each do |c| %>
<%= label(c, c) %>:
<%= f.radio_button(:category, c, :class => "date-format-switcher", checked: (c=='One-Shot')) %>
<% end %>
<div id='id_of_first_div'>
<%= f.date_select :deadline %>
</div>
<div id='id_of_second_div'>
<%= f.date_select :date_started %>
</div>
<% end %>
<script>
$(function(){
$('#id_of_second_div').hide();
$('#challenge_category_one-shot').click(function(){
$('#id_of_first_div').show().attr('disabled', false);
$('#id_of_second_div').hide().attr('disabled', true);
});
$('#challenge_category_ongoing').click(function(){
$('#id_of_first_div').hide().attr('disabled', true);
$('#id_of_second_div').show().attr('disabled', false);
});
});
</script>
Radio Button HTML
<input class="date-format-switcher" type="radio" value="One-Shot" checked="checked" name="challenge[category]" id="challenge_category_one-shot" />
<input class="date-format-switcher" type="radio" value="Ongoing" name="challenge[category]" id="challenge_category_ongoing" />
Adapting Fiddle
<input id='a-selector' type='radio' name='selector' value='A' checked/> A
<input id='b-selector' type='radio' name='selector' value='B'/> B
<div id='details'>
<div id='for-a'>
<%= f.date_select :deadline, include_blank: true, selected: Date.current %>
</div>
<div id='for-b'>
<%= f.date_select :date_started, include_blank: true, selected: Date.current %>
</div>
</div>
<script>
var removed = $('#for-b').detach();
$('#a-selector').click(function() {
$('#details').append(removed);
removed = $('#for-b').detach();
})
$('#b-selector').click(function() {
$('#details').append(removed);
removed = $('#for-a').detach();
})
</script>
Setting a form element as disabled only disables user interaction with it; it doesn't remove it from the form's data (although your jQuery code is actually setting the div to disabled, which does nothing, but fixing that wouldn't help at all). What you want to do instead is clear the value of the date elements, e.g.,
<script>
$(function(){
$('#id_of_second_div').hide();
$('#challenge_category_one-shot').click(function(){
$('#id_of_first_div').show();
$('#id_of_second_div').hide();
$('#id_of_second_div select').value('')
});
$('#challenge_category_ongoing').click(function(){
$('#id_of_second_div').show();
$('#id_of_first_div').hide();
$('#id_of_first_div select').value('')
});
});
</script>
Though for that to work, you will need to add include_blank: true as an option to your date_select tags:
<%= f.date_select :deadline, include_blank: true %>
This will add the empty value as an option to your date selects, so that the above code can reset them to that empty value.
I'd also like to note -- all of this is just front-end logic, which any malevolent (or curious) user can circumvent. Your backend code (i.e., your controller) should handle discarding the fields you don't need based on your business logic, too.
Related
I have a table "fundings" in which there is a field "status", for which i have a select field in the form. The options for this select field are ["approved", "declined", "pending"]. What i want is when "declined" is selected, a further text box shows to explain the reason for decline. Please help how can this be done.
<%= form_for([#parent, #child, #funding], :html => {class: "form-horizontal",role: "form"}) do |form| %>
<div class = "form-group">
<div class="control-label col-sm-2">
<%= form.label :status %>
</div>
<% if current_user.admin? %>
<div class="col-sm-8">
<%= form.select :status,['Pending', 'Approved', 'Declined'], class: "form-control" %>
</div>
<% else %>
<!-- Disabled for non-admin users -->
<% end %>
</div>
<!-- Submit button here -->
<% end %>
Update
<div class="form-group">
<%= "Status" %>
<%= form.select :status, ['Pending', 'Approved', 'Declined'], {}, id: "sample-status-select", class: "form-control" %>
</div>
<div class="form-group">
<%= "Decline Reason" %>
<%= form.text_area :decline_reason, class: "form-control hidden", id: "decline-reason-textarea" %>
</div>
</div>
<div class="form-group">
<div class="col-sm-10">
<%= form.submit "Apply", class: 'btn btn-primary btn-lg' %>
</div>
</div>
</div>
</div>
<% end %>
<script type="text/javascript">
<plain>
$(function() {
$("#sample-status-select").on("change", function() {
var select_val = $(this).val();
console.log(select_val);
if (select_val === 'Declined') {
$("#decline-reason-textarea").removeClass("hidden");
} else {
$("#decline-reason-textarea").addClass("hidden");
$("#decline-reason-textarea").val("");
}
});
});
</plain>
</script>
$(function() {
$("#sample-status-select").on("change", function() {
var select_val = $(this).val(); // this gets the value of the dropdown menu
console.log(select_val); // this just displays the selected value in the browser console (if you have the browser console open)
if (select_val === 'Declined') {
// if the 'Declined' option is chosen
// we remove the 'hidden' class from the textarea
$("#decline-reason-textarea").removeClass("hidden");
} else {
// if any other option is chosen
// we put back the 'hidden' class to the textarea
// also, we update the textarea value to BLANK (this part is optional, it depends if you want to keep the value of the textarea)
$("#decline-reason-textarea").addClass("hidden");
$("#decline-reason-textarea").val("");
}
});
});
.hidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="https://httpbin.org/post" method="post">
Status
<select id="sample-status-select">
<option value="Pending">Pending</option>
<option value="Approved">Approved</option>
<option value="Declined">Declined</option>
</select>
<br>
<br> Decline Reason
<textarea id="decline-reason-textarea" class="hidden">
</textarea>
</form>
Check this snippet I made. It should work for you as well.
This is a basic html form so this works even without ruby on rails.
After you get the gist of this, you should be able to port for it to work with your rails app.
<script type="text/javascript">
$(function() {
$("#sample-status-select").on("change", function() {
var select_val = $(this).val();
console.log(select_val);
if (select_val === "Declined") {
$("#decline-reason-textarea").removeClass("hidden");
} else {
$("#decline-reason-textarea").addClass("hidden");
$("#decline-reason-textarea").val("");
}
});
});
</script>
I've moved from BS3 to Materialize so I am going through and changing my forms - I have 4 forms that are extremely similar, but as I switched the first one over it's no longer submitting. The button doesn't even seem like it's getting clicked, but I tied a generic 'logMe' function to it and sure enough it is.
My routes are the exact same for both, the new form is
<div class="row">
<%= form_with(model: #statement, local: true) do |form| %>
<% if #statement.errors.any? %>
<% #statement.errors.full_messages.each do |message| %>
<script>
$(function() {
Materialize.toast("<%= message %>", 3000);
});
</script>
<% end %>
<% end %>
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">account_circle</i>
<!--<label for="icon_prefix">SoW Type:</label>-->
<%= form.label :statement_type, 'Type:' %>
<%= form.text_field :statement_type, :id => "disabled", :value => (params[:statement_type]), readonly: true, :disabled => true %>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<i class="material-icons prefix">contacts</i>
<%= form.label :name, "Name:" %>
<%= form.text_field :name, :id => 'required_field1' %>
</div>
<div class="input-field col s6">
<i class="material-icons prefix">contacts</i>
<%= form.label :cost, "Cost:" %>
<%= form.text_field :cost, :id => 'required_field2' %>
</div>
</div>
<div class="row">
<div class="input-field col s6">
<i class="material-icons prefix">date_range</i>
<%= form.label :start_date, "Start Date" %>
<%= form.text_field :start_date, :class => 'datepicker', "data-provide" => 'datepicker', :id => 'required_field4', :placeholder => "YYYY-MM-DD" %>
</div>
<div class="input-field col s6">
<i class="material-icons prefix">date_range</i>
<%= form.label :end_date, "End Date" %>
<%= form.text_field :end_date, :class => 'datepicker', "data-provide" => 'datepicker', :id => 'required_field5', :placeholder => "YYYY-MM-DD" %>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<i class="material-icons prefix">perm_contact_calendar</i>
<%= form.collection_select(:client_id, current_user.clients.order(:name),:id,:name, :class => "browser-default", :prompt => "Choose a client" ) %>
</div>
</div>
<div class="row">
<div class="col s12">
<%= form.submit 'Submit', :class =>'btn btn-default', :id => 'register', :onclick => "testMe()"%>
</div>
</div>
<% end %>
</div>
<script type="text/javascript">
$(document).ready(function (){
$('select').material_select();
validate();
$('#required_field1, #required_field2').change(validate);
});
function testMe(){
console.log('hi')
}
function validate(){
if ($('#required_field1').val().length > 0 &&
$('#required_field2').val().length > 0
){
$("input[type=submit]").prop("disabled", false);
}
else {
$("input[type=submit]").prop("disabled", true);
}
}
var from_$input = $('#required_field4').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15, // Creates a dropdown of 15 years to control year,
today: 'Today',
clear: 'Clear',
close: 'Ok',
closeOnSelect: true,
format: 'yyyy-mm-dd'
}),
from_picker = from_$input.pickadate('picker')
var to_$input = $('#required_field5').pickadate({
selectMonths: true, // Creates a dropdown to control month
selectYears: 15, // Creates a dropdown of 15 years to control year,
clear: 'Clear',
close: 'Ok',
closeOnSelect: true,
format: 'yyyy-mm-dd'
}),
to_picker = to_$input.pickadate('picker')
// Check if there’s a “from” or “to” date to start with.
if ( from_picker.get('value') ) {
to_picker.set('min', from_picker.get('select'))
}
if ( to_picker.get('value') ) {
from_picker.set('max', to_picker.get('select'))
}
// When something is selected, update the “from” and “to” limits.
from_picker.on('set', function(event) {
if ( event.select ) {
to_picker.set('min', from_picker.get('select'))
}
else if ( 'clear' in event ) {
to_picker.set('min', false)
}
})
to_picker.on('set', function(event) {
if ( event.select ) {
from_picker.set('max', to_picker.get('select'))
}
else if ( 'clear' in event ) {
from_picker.set('max', false)
}
})
</script>
I've tried commenting out all JS, switching it to a regular button, linting it and using Rubocop but I don't see anything off. I went through the HTML to make sure the button was inside the form, and it is.
This isn't the first form I've transitioned, but the first I'm having issues with.
(I assume only the view is relevant since it isn't getting to the controller at this point.)
Just to be safe - The view rendering the form is
<div class="row">
<div class="col s12"><span class="flow-text" style="text-align: center;"><h1>New <%= params[:statement_type] %></h1></span></div>
</div>
<% if params[:statement_type] == 'Proposal' %>
<%= render 'proposal_form' %>
<% elsif params[:statement_type] == 'Concept' %>
<%= render 'concept_form' %>
<% elsif params[:statement_type] == 'SoW' %>
<%= render 'sow_form' %>
<% elsif params[:statement_type] == 'Misc' %>
<%= render 'misc_form' %>
<% end %>
<%= link_to 'Back', statements_path %>
SoW + Proposal work. SoW doesn't.
My issue ended up not being HTML based, but Rails based in the end.
My static element that is populated by a param was causing the issue.
<%= f.text_field :statement_type, :id => "disabled", :value => (params[:statement_type]), readonly: true %>
By removing the id: disabled it resolved the inability for the Submit button to submit. Unfortunately, it also makes MaterializeCSS back to highlighting the field when I select it, but my issue was the Submit button not working.
What is the best way I can make One-Shot the default radio button selection?
_form
<% Challenge::CATEGORY.each do |c| %>
<span class="label label-primary"> <%= label(c, c) %> </span>
<%= f.radio_button(:category, c, :class => "date-format-switcher") %>
<% end %>
<div id='id_of_first_div'>
One-Shot
</div>
<div id='id_of_second_div'>
Ongoing
</div>
<script>
$(function(){
$('#challenge_category_one-shot').click(function(){ $('#id_of_first_div').show(); $('#id_of_second_div').hide(); });
$('#challenge_category_ongoing').click(function(){ $('#id_of_first_div').hide(); $('#id_of_second_div').show(); });
});
</script>
challenge.rb
scope :oneshot, -> { where(categories: 'One-Shot') }
scope :ongoing, -> { where(categories: 'Ongoing') }
CATEGORY = ['One-Shot', 'Ongoing']
schema
t.string "category"
If you are intent on using f.radio_button then you could add the parameter
checked: (c=='One-Shot')
You could also use r.collection_radio_buttons instead:
<% categories = ['One-Shot', 'Ongoing'] %>
<%= f.collection_radio_buttons :category, categories, :to_s, :to_s, {checked: 'One-Shot'} %>
I currently have a rather complicated _request_form for creating new Requests in my website. Currently, when creating a request, employees must choose their name from a dropdown menu like so:
<%= f.collection_select :name, Employee.all(:order => 'name'), :name, :name %>
This selects puts the right Employee in the Request. However, on the off chance the employee isn't in database I'd like an other option in the collection_select that spawns two textboxes (for Employee name and email), and upon form submission makes the new Employee.
I assume this requires some sort of fancy Ajax, but my limited Rails knowledge doesn't extend that far!
Edit:
Here's my full view:
<%= javascript_include_tag :defaults, "nested_form" %>
<div class="request_form">
<% if !#request.errors.empty? %>
<div class="alert alert-error">
<ul>
<% #request.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="well">
<%= nested_form_for #request, html: { multipart: true } do |f| %>
<%= f.label :title %><br />
<%= f.text_field :title %><br /><br />
<%= f.label :name, 'Submitted By' %><br />
<%= f.select :name, Employee.sorted_employees_list.map { |value| [ value, value ] }, :id => "employee_box" %><br />
<div id="new_employee_data">
</div>
<%= f.label :description %><br />
<%= f.text_area :description %><br /><br />
<%= f.label :attachment_uploader, 'Attachments' %><%= f.file_field :attachment_uploader, :multiple => true, name: "data_files[attachment_uploader][]" %><br />
<% unless #request.data_files.empty? %>
<%= f.label :attachment_uploader, 'Current Attachments:' %><br />
<% end %>
<%= f.fields_for :data_files do |attachment| %>
<% if !attachment.object.new_record? %>
<%= attachment.label :attachment_uploader, 'Delete: ' + attachment.object.attachment_uploader_url.split("/").last %>
<%= attachment.check_box :_destroy %>
<% end %>
<% end %>
</div>
</div>
<script>
$(document).ready(function(){
$('#employee_box').append("<option>Other</option>");
});
$('#employee_box').change(function() {
if( $('#employee_box').val() === 'other' ) {
$('#new_employee_data').append("<input type='text' id='employee_name' placeholder='Employee Name'> <br/> <br /></input><input type='email' id='employee_email' placeholder='Employee Email'> </input>");
}else {
$('#employee_name').remove();
$('#employee_email').remove();
}
});
</script>
This includes #Kirti's suggestion. However, I can't seem to make it work!
Popup dialog is good choice, I think!
1) Add to your Gemfile, and run bundle:
gem 'jquery-ui-rails'
2) Activate jquery-ui javascript (application.js):
//= require jquery.ui.dialog
3) Link jquery-ui stylesheets (application.css):
*= require jquery.ui.dialog
4) Prepare data for select (employees_controller.rb)
def new
#prices = Price.all.map{|p| [p.price, p.id] }
#prices << ['Create New', 'new_id']
end
5) Display select component on view (employees/new.html.erb):
<%= select_tag :employee, options_for_select(#employees) %>
<div id="new_employee_dialog">
<label for="name" type="text">Employee name:</label>
<input name="name" type="text"/>
<label for="email" type="text">Employee email:</label>
<input name="email" type="email"/>
</div>
6) This javascript work with dialog window and send ajax request (assets/javascripts/employees.js.coffee):
$ ->
$("#new_employee_dialog").dialog
modal: true
width: 400
height: 300
autoOpen: false
draggable: false
dialogClass: "without-header"
buttons: [
text: "Cancel"
click: ->
$(this).dialog "close"
,
text: "Ok"
click: ->
modalForm = $(this)
$.post "/users/form_create",
employee_name: $(modalForm).find("input[name='name']").val()
employee_email: $(modalForm).find("input[name='email']").val()
, (data, status) ->
if data['status'] == 'ok'
modalForm.dialog "close"
alert "Ok"
else
alert "Oops"
]
$('#employee').change ->
selected_employee_id = jQuery("#employee").val()
console.log('selected id: ' + selected_employee_id )
if selected_employee_id == 'new_id'
$("#new_employee_dialog").dialog("open");
7) Create method to catch ajax request on server-side (employees_controller.rb):
def form_create
employee_name = params[:employee_name]
employee_email = params[:employee_email]
# create new user..
respond_to do |format|
format.json { render :json => {status: 'ok'} }
end
end
8) Add it to routes.rb:
post 'users/form_create' => 'users#form_create'
Add an empty div tag(placeholder) where you want to spawn the two input fields:
<div id="new_employee_data">
</div>
Add the following jQuery at the bottom of the view:
<script>
$(document).ready(function(){
$('#request_name').append("<option value='other'>Other</option>");
});
$('#request_name').change(function() {
if( $('#request_name').val() === 'other' ) {
$('#new_employee_data').append("<input type='text' id='employee_name' placeholder='Employee Name'> <br/> <br /></input><input type='email' id='employee_email' placeholder='Employee Email'> </input>");
}else {
$('#employee_name').remove();
$('#employee_email').remove();
}
});
</script>
where,
replace #request_name with the id generated for your collection_select.
You will also need to add code for creating the new employee in the action which is executed at form submission.
NOTE: I am no expert in AJAX but you could adapt the above jQuery and take it from there.
I have a checkbox and before I click on a submission button, I want to check if a checkbox is empty? if it is checked, a notification error should be shown.
<script src="/assets/rails.validations.js" type="text/javascript"></script>
<%= form_for Groupsnorm.new, url: what_to_do_arraydbs_path ,method: :get ,:validate => true do |f| %>
<div class="field_label">
<%= f.label :group_name%>:
</div>
<div class="field">
<%=f.text_field :group_name %>
</div>
<%= submit_tag "Submit", :commit =>"pictures" %>
<% #files.each do |file| %>
<p><td> <%= check_box_tag "files[]", file.id %></td><%= arraydb.arraydb_file_name %></p>
<%end%>
<%end%>
and JavaScript looks something like this:
$(function validateCheckbox() {
$('#notifications').ready(function() {
$.notification(
{
content: text,
showTime: false,
timeout: 5000,
icon: "9",
}
);
});
});
How is it possible to check if the checkbox is empty? Or is it possible to do a client side validation so that "submit" button will not be clickable if checkbox is empty?
in you controller write
if params[:CheckBoxNameAttribute]
{
// source code here
}
this checks whether your checkbox is checked or not