add checkbox content to text field - ruby-on-rails

New to rails, also not great in english... I need some advice please.
I have a form with a non-exhaustive list of drugs. The user can select drugs with check-boxes.
There is a check-box called "Other" which makes a text field appear (with a JS script).
The content of this text field is saved in my database under the column :taken_drugs
Here is the code I got until now :
= form_for #quizz, :url => { :action => "create" } do |f|
h4 Which drugs did you take ?
h5 (You can answer more than one)
.field class="list-group"
div class="list-group-item"
= check_box("LSD", "yes")
= label_tag 'LSD'
div class="list-group-item"
= check_box("Psilocybine", "yes")
= label_tag 'Psilocybine (mushrooms)'
div class="list-group-item"
= check_box("DMT", "yes")
= label_tag 'DMT (ayahuasca)'
div class="list-group-item"
= check_box("other", "other", {}, "yes", "no")
= label_tag 'other'
div id="disappear_consomme" style="display:none"
p Which other drugs did you take ?
= f.text_field :taken_drugs
=f.submit
How can I have a result where I save to :taken_drugs the drugs that are checked AND the drugs that are added to the text field ?
Examples of what I need :
if the user check "LSD" and "DMT" I have "LSD DMT"
if the user check "LSD" and write "CANNABIS VALIUM" I have "LSD CANNABIS VALIUM"

You have two options, you can either catch this data in the front end with javascript or you can catch it in the back end with Ruby before it is posted to your database.
The js way:
var text = "";
for (var i = 0; i < form.elements.length; i++ ) {
if (form.elements[i].type == 'checkbox') {
if (form.elements[i].checked == true) {
text += form.elements[i].value + ' ';
}
}
}
Stick that in a function. Call it from your submit button with an onClick or onSubmit event handler.
The ruby way would be handled in your rails controller create method and parsing through whatever you are passing up in your params hash.

Related

Is it possible to create dynamic label name for nested attributes created by cocoon gem?

I created a form with nested attribute using cocoon gem. When link_to_add_association was clicked, it will append the label and text_field. However, I would want the label name to be dynamic in the sense that the label name for every label will be different. For instance, I would like to have 'A:' as label name for first label, 'B:' for the second label, and so on and so forth. Is it possible to achieve this?
/_mcq.html.erb
<%= f.fields_for :mcq_options do |option| %>
<%= render 'question_paper_generations/mcq_option_fields', f: option %>
<% end %>
<div><%= link_to_add_association 'Add Option', f, :mcq_options %></div>
/_mcq_options_fields.html.erb
<%= f.label :option %>
<%= f.text_field :option, class: 'form-control' %>
Assuming your nested fields are inside a div "#options"
$(document).ready(function() {
var next_label = "A";
def next_char(c) {
next = "A";
if (c != "Z") {
next = String.fromCharCode(next.charCodeAt(0) + 1);
};
return next;
};
$('#options').on('cocoon:after-insert', function(e, added_option) {
added_option.find("label").first().text(next_label+":");
next_label = next_char(next_label);
});
});
EDIT
To use roman numbers: (taken from: https://stackoverflow.com/a/32851198/3372172). Note. There are comments saying this could not work because objects have no order. You should test it, or choose other implementation (you can find similar solutions in the same link).
$(document).ready(function() {
var next_label = 1;
function romanize(num) {
var lookup = { M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1};
var roman = '';
var i;
for ( i in lookup ) {
while ( num >= lookup[i] ) {
roman += i;
num -= lookup[i];
}
}
return roman;
};
$('#options').on('cocoon:after-insert', function(e, added_option) {
added_option.find("label").first().text(romanize(next_label)+":");
next_label++;
});
});

If Else in HAML to check the value of a "select" box

= form_tag questions_path, :method=>:post do
= label :question, :type, 'Type: '
= select :question, :type, %w(Text Picture Audio Video), :id=> :question_type_combo
**- if :question_type_combo.selected != 'Text'**
= label :question,:url, 'URL: '
= text_field :question,:url, :id=> :question_url_text
= submit_tag 'Add Question',:id=>:add_question_button
Is something of this sort possible in HAML? I wish to render the textfield only for certain options if selected in the SELECT BOX above.
Yes and no. You can write a conditional based on the values of the record that you bind to the form:
= form_for #question do |f|
= f.label :type
= f.select, :type, %w(Text Picture Audio Video), id: 'question_type_combo'
- unless f.object.question_type_combo === 'Text'
= f.label :url
= text_field :url, id: 'question_url_text'
But this would only change the visibility after the user submits the form and not be very useful.
Instead you can just use jQuery to create an event handler for the ´change´ event.
$(document).on('change','#question_type_combo', function(){
var type = $(this).first(':selected').val();
var $other_input = $('#other_input');
if (type == 'Text') {
$other_input.hide();
} else {
$other_input.show();
}
});
// sets the initial state
// if you are using turbolinks
$(document).on('page:load', function(){
$('#question_type_combo').trigger('change');
});
// if you are not using turbolinks
$(function(){
$('#question_type_combo').trigger('change');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<div class="field">
<label>Type</label>
<select name="question[question_type_combo]" id="question_type_combo">
<option>Text</option>
<option>Something else</option>
</select>
</div>
<div class="field" id="other_input">
<label>URL</label>
<input type="text" name="question[url]">
</div>
</form>
- if :question_type_combo.selected != 'Text' This is not possible in the haml view, If you want to do something based on selected option you have to use js.
Or you may set the selected option using similar code if you have controller objects:
= select_tag("fee_discount", options_for_select(Fee.discounts.keys.map {|k| [k.titleize, k]}, selected: "#{"rewards" if #vendor.present? && #vendor.approved?}"), include_blank: true)
Or
You may keep the label and text_field inside a div with hide class.
And then using javascript you may hide unhide the div.

Rails check_box_tag - get all the values checked in view(haml) file

So I have multiple checkboxes on my page. I collect all of them like shown in the code below. I would like to access the values of the array before passing it on to the controller
= check_box_tag "names[]", ob.name, false, class: 'cbx'
I am able to pass them with my older code
%fieldset.actions
= form.submit "Upgrade", :class => 'button'
Logs:
Processing by SomeController#create as HTML Parameters:
{"utf8"=>"✓",
"names"=>["ron", "jacob"], "commit"=>"NameButton"}
Ok. So i would like to access all values in my haml files. Is there a way before i submit my form, I can access which checkboxes are selected.
I would like to pass the names[] to my controller as a parameter.
=link_to script_name1, { :action => 'create', :names => 'dontknowhowtopassnames[]' }, :method => :post
Rails version - 3.2.17
You can do that using Javascript.
The exact implementation depends on what exactly you want to do with those values, but you could, for example, use the change event to track and maintain an array of all checked values :
/*
* should properly init this array if some of your checkboxes are already
* checked when the form is loaded
*/
var names = [];
$(document).ready(function() {
$(document).on('change', '.cbx', function() {
var name = $(this).val();
var idx = names.indexOf(name);
if ($(this).prop('checked') && idx === -1) {
names.push(name);
} else if (!($(this).prop('checked')) && idx >= 0) {
names.splice(idx, 1);
}
});
});
Updated with complementary answer:
To submit a form with a link instead of a button:
In your view, replace
%fieldset.actions
= form.submit "Upgrade", :class => 'button'
with
= link_to "Submit", "#", :class => 'submit_link'
Then in your Javascript, add the following inside the $(document).ready body:
$(document).on('click', 'a.submit_link', function(e) {
$(this).closest('form').submit();
e.preventDefault();
});
And that's it. You're making your life very complicated by trying to serialize the form data on your own while the form's submit() method can take care of it for you. You can serialize data on your own, and it's sometimes useful, for instance when dealing with AJAX, but in your case the default submit() is perfect for the job.

Dynamically insert ruby generated HTML

I have a form where a user can elect to create more input areas (to provide more information). I have a link the user will click on and then the extra form inputs will be created. I'd like to use the rails form helpers so that I don't have to write the html myself. I've tried inserting the form helpers directly into coffeescript and saving the outputted html to a data tag on the link, but I can't get the coffeescript to execute the ruby code and I'm having escaping issues with the data attribute.
Here's the form:
= simple_form_for([#site, #zone]) do |f|
= f.error_notification
.form-inputs
= f.input :site_id
= label_tag "X"
= text_field_tag 'x_coords[]'
= label_tag "Y"
= text_field_tag 'y_coords[]'
= label_tag "X"
= text_field_tag 'x_coords[]'
= label_tag "Y"
= text_field_tag 'y_coords[]'
= label_tag "X"
= text_field_tag 'x_coords[]'
= label_tag "Y"
= text_field_tag 'y_coords[]'
= link_to "Add Point", "#", id: "add_point", data: { fields: label_tags }
.form-actions
= f.button :submit
When a user clicks the "Add Point" link, I'd like to add another block of:
= label_tag "X"
= text_field_tag 'x_coords[]'
= label_tag "Y"
= text_field_tag 'y_coords[]'
label_tags is in application_helper.rb:
def label_tags
label_tag "Z"
end
The problem is the output for the "Add Point" link is:
Z" id="add_point">Add Point
and the quotation marks are causing the link to come out with the text: "Z" id="add_point">Add Point"
I got the data attribute idea from this screencast
You cannot execute Ruby code from Javascript. When the page is requested all embedded ruby is evaluated and the results are what you get. The issue that I can see from you paste is that your label block is in the right data attribute but it's not escaped.
What you'll need to do is escape the quotes on the generated HTML going into that field and then unescape them via Javascript. You could use html_escape here like: data: { fields: h(label_tags) } (h is an alias for html_escape or you could do this yourself, manually.
def escape(str)
str.gsub(/</, "<").gsub(/>/, ">").gsub(/"/, """)
end
# later in the view for the form
data: { fields: escape(label_tags) }
And then your CoffeeScript would click handler would like:
function unescape(str) {
return str.replace(/((?:<)|(?:>)|(?:"))/g, function($1) {
switch($1) {
case ">":
return ">";
case "<":
return "<";
case """:
return '"';
}
});
}
$("a").on("click", function() {
var html = unescape(this.data("fields"));
$(".the-place-to-put-it").html(html);
});
I do not doubt a better solution exists and as of the posting of this answer I have not tested this to work (in theory it should). Ideally, you should just generate the elements with jQuery in Javascript and not depend on this method for doing this - yes, it's duplicate code duplicated between ruby and Coffee.
Simple solution for me was to replace the double quotes in my generated HTML with single quotes. In code:
= link_to "Add Point", "#", id: "add_point", data: { fields: label_tags.gsub("\"", "'") }
Also, had to use capture and concat in the helper method:
module ApplicationHelper
def label_tags
capture do
concat label_tag "X"
concat text_field_tag 'x_coords[]'
concat label_tag "Y"
concat text_field_tag 'y_coords[]'
end
end
end

RoR Displaying associated records based on select menu option

I am new to RoR and I am looking for a way to dynamically display values in some text fields depending on the option chosen from a select menu in a form. The associated records are stored in another table. Hopefully in a way AJAX can be used such that it wouldn’t require a page refresh. I have seen examples in which select menus are dynamically changed according to values of select menus but not text fields.
Thanks,
Alex
PS: I am using rails 3.
Here's how I did it. I'm a Rails beginner too, so this may not be the best/most efficient way, but it works:
JS:
$('#select_box_id').live('change', function() {
var select_field_val = $('#select_box_id').val();
if(select_field_val == "") select_field_val = "0";
$.get('/some_controller_action/' + select_field_val, function(data) {
$('#text_field_div').html(data);
});
return false;
});
Controller:
def some_controller_action
#some_processing...
result = whatever
render :partial => "my_partial", :locals => { :text_field_value => result }
end
View:
<div id="text_field_div">
<%= render :partial => 'my_partial', :locals => { :text_field_value => "" } %>
</div>
Partial:
<%= text_field_tag :text_field, text_field_value %>

Resources