= 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.
Related
I have a form where a user selects a school, and then a qualification that the school provides:
<div class="row">
<div class="col-md-6">
<%= f.association :education_organization,
collection: EducationOrganization.active,
include_blank: true
%>
</div>
<div class="col-md-6">
<%= f.association :training_qualification,
collection: TrainingQualification.active,
include_blank: true
%>
</div>
</div>
I would like to dynamically scope the qualifications select to only show the qualifications available to the school that is selected.
I don't want to do an ajax call, I'd rather send the whole list at the start and have the client switch the select options offline.
What's the best way to do this?
I found a way, by initially loading all options, then storing the html options and filtering that list by the id of the association as a data attribute.
View:
<%= f.association :education_organization,
collection: EducationOrganization.active,
include_blank: true
%>
<%= f.association :training_qualification,
collection: TrainingQualification.active.map { |tq| [tq.name, tq.id, {data: {org: tq.education_organization.id}}] },
include_blank: true
%>
JS:
$(function(){
// this is a hack that lets the JS be included anywhere, but only run on pages with the relevant form
var qualifications_select = $('#user_training_qualification_id');
if(qualifications_select) {
// this stores all select options
var qualification_options = qualifications_select.html();
function updateQualSelect(qualifications_select) {
var selected_org_id = $('#user_education_organization_id :selected').val();
if(selected_org_id != '') {
var filtered_options = $(qualification_options).filter(`[data-org=${selected_org_id}]`);
qualifications_select.html(filtered_options);
} else {
qualifications_select.empty();
}
}
// this line filters the select when the other select changes
$('#user_education_organization_id').change(function() {
updateQualSelect(qualifications_select);
});
// this line filters the select on page load
updateQualSelect(qualifications_select);
}
})
I have a mix of ruby rails code
I have a form with a selection option that i want to be a required, and i want to validate. If user do not select anything i want to validade with a error message.
However, I try to copy past code from internet, I'm new at ruby rails and I still not have a error message.
I also check that i use 'required' , or if i use 'validates_presence_of' doesn't make difference because it's a submit form (i think)
test_filteR_form.rb
class TestFilterForm < ApplicationForm
attribute :model, String
validates_presence_of :model
end
.html.erb
<%= f.input :fill_form_error_message,:as => :hidden, :input_html => { :value =>I18n.t('test.fill_form_error') } %>
<%= f.input :model, label: I18n.t('test.filters.model'), autofocus: true, input_html: {class: 'input-xlarge chosen-select' }, collection: TestType.options_for_select, include_blank: true %>
"/>
controller
def paginate
#test_form = TestForm.new(params)
unless #test_form.valid?
#model = params[:test_filter_form][:model]
#h_model = #model.pluralize + 'H'
#history, _query, #test_fields = TestQueryService.search!(params)
session[:test_query] = _query
session[:test_klass] = #model
else
format.json { render :json => { :error => #test_form.errors.full_messages }, :status => 422 }
end
js.coffee
$contentDiv.on 'ajax:error', 'form[data-value]', (event, xhr, status, error) ->
data = $.parseJSON(xhr.responseText)
$result = $(#).parents('tr').find('[data-result]')
controller.resultUpdateError xhr.status, $result.data('result'), data, $(#)
# Hide row loading spinner
$(#).parents('tr').find('span[role="result_update_spinner"]').hide()
# Hide saved form
$(#).parents('tr').find('.saved_form').hide()
resultUpdated: (result, data, $form) ->
if data.flash != undefined
# Sets a sucess message on page top
flash data.flash.type, data.flash.message
# Sets a success message on row
$fieldForm = $form.parents('tr').find(".messages")
$fieldForm.find('.controls').empty()
$fieldForm.find('.control-group .controls').css('color', 'green').append #_inlineMessage("Gravado com sucesso")
# Hide success message after some time
setTimeout ((self) ->
->
$fieldForm.find('.control-group .controls').empty()
return
)(this), 4000
Since you are dynamically created the selection box then there must be a default value selected which is not nil so there is no change seen you can manually create selection like this:
<div class="form-group">
<%= f.label :select_user_country %><br/>
<select class="form-control select2" name="user[country_id]">
<option value="" selected disabled>Select a Country</option>
<%#countries.each do |country|%>
<option value="<%=country.id%>"><%=country.name%></option>
<%end%>
</select>
</div>
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.
I use the simple_form gem and I want a simple character counter on a text field. I was told, this might work:
add this to the form:
<%= f.input :body, id: "body-field" %>
<span id="body-count">0 characters</span>
and javascript:
$("#body-field").on("keyup", function(){
length = $(this).val().length;
$("#body-count").html(length);
});
I got this information from here (Attention: It is full of advertisement): http://www.sohua.xyz/questions-full/4320915/how-do-i-implement-a-basic-character-counter-in-a-simple-form
I did this, but nothing happens. Here is my actual code chapters/new.html.erb:
<%= simple_form_for([#book, #book.chapters.build]) do |f| %>
<%= f.input :chaptertitle %>
Mininmum amount of characters: <%= #book.min_length %> Maximum amount of characters: <%= #book.max_length %>
<%= f.input :chaptercontent, id: "body-field" %>
<span id="body-count">0 characters</span>
<%= f.input :author %>
<%= f.button :submit %>
<% end %>
<script>
$("#body-field").on("keyup", function(){
length = $(this).val().length;
$("#body-count").html(length);
});
</script>
Can you give me any advice, how to get it work?
You need to wrap your code in jquery document ready function:
$(function() {
$("#body-field").on("keyup", function(){
var length = $(this).val().length;
$("#body-count").html(length);
});
});
Why don't you use an existing library instead?
https://github.com/dtisgodsson/jquery-character-counter
You might want to use either js or coffee-script, I am providing a coffee script example below:
Add this piece of code to your chapters.coffee file:
ready = ->
totalChars = 100
#Total characters allowed
countTextBox = $('#body-field')
# Remaining chars count will be displayed here
charsCountEl = $('#countchars')
#initial value of countchars element
charsCountEl.text totalChars
#user releases a key on the keyboard
countTextBox.keyup ->
#get chars count in Text field
thisChars = #value.replace(/{.*}/g, '').length
if thisChars > totalChars
# total extra chars to delete
CharsToDel = thisChars - totalChars
#remove excess chars from text field
#value = #value.substring(0, #value.length - CharsToDel)
else
#count remaining chars
charsCountEl.text totalChars - thisChars
return
return
$(document).ready ready
$(document).on 'page:load', ready
# Loads javascript while loading page
Add this line to your form right below to the Text input field.
var ready;
var charsCountEl, countTextBox, totalChars;
totalChars = 100;
countTextBox = $('#body-field');
charsCountEl = $('#countchars');
charsCountEl.text(totalChars);
countTextBox.keyup(function() {
var CharsToDel, thisChars;
thisChars = this.value.replace(/{.*}/g, '').length;
if (thisChars > totalChars) {
CharsToDel = thisChars - totalChars;
this.value = this.value.substring(0, this.value.length - CharsToDel);
} else {
charsCountEl.text(totalChars - thisChars);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="text" id="body-field" />
<span id="countchars"></span>
If your file under javascript/ folder doesn't have extestion .coffee the please rename it to chapters.coffee if it does then thats it.
PS: here is the javascript version of the same http://pastebin.com/LZb1DAC4.
Reference: https://stackoverflow.com/a/24629105/2545197
This solution won't be as good as Abhinay's solution, but it works for me:
(Please note, I'm an amateur, this code may be horrendous)
Javascript code:
<script>
$(document).ready(function(){
var choosingbar = function( event ){
$(event.target).parents(".counting").children(".count").text($(event.target).val().length);
};
$(".counting textarea").keyup(choosingbar);
});
</script>
new.html.erb code:
<%= simple_form_for([#book, #book.chapters.build]) do |f| %>
<%= f.input :chaptertitle %>
Mininmum amount of characters: <%= #book.min_length %> Maximum amount of characters: <%= #book.max_length %>
<div class="counting" ><%= f.input :chaptercontent %>Characters: <span class="count"></span></div><br>
<%= f.input :author %>
<%= f.button :submit %>
<% end %>
I'm using simple_form with AngularJS:
= simple_form #post do |f|
= f.input :title, input_html: { "ng-model" => "title" }
It works great for my scenario on new post, but for editing on existing post, it doesn't bind/fill in existing value from post's title on form. From what I thought Rails already fill in the value, but AngularJS wipes it out after the page load because $scope.title is blank.
I found the trick is to actually create a controller with an init function that takes the value you want. In my case I just created a app/assets/javascripts/angular_app.js file that looks like this:
//= require_self
AngularRails = angular.module('AngularRails', []);
AngularRails.controller('PostFormCtrl', function($scope) {
$scope.init = function(title) {
$scope.title = title;
}
});
You'll have to translate the view into haml but it should look something like this:
<div ng-app="AngularRails">
<div ng-controller="PostFormCtrl" ng-init="init('<%= #post.title %>')">
<%= form_for #post, html: {name: "postForm", "novalidate" => true} do |f| %>
<%= f.text_field :title, "ng-model" => "title", required: true %>
<%= f.submit "ng-disabled" => "postForm.$invalid" %>
<% end %>
</div>
</div>
Remember to include the angular_app file into application.js and it should world. Obviously, this isn't a very robust solution but you could use active model serializer to convert the rails object to a json object. Then, pass that json object to the init function and in the controller, iterate over the key/value pairs of that json object and set them to $scope. Something like this:
AngularRails.controller('PostFormCtrl', function($scope) {
$scope.init = function(input) {
Object.keys(input).forEach(function(key) {
$scope[key] = input[key];
});
};
});
Hope that helps!