Rails passing value to hidden field using javascript - javascript

I have an array structured as follows:
<% #locations = [['Town 1',2],['Town 2',2]...] %>
That I pass through an options_for_select tag that passes the shows the town name correctly and passes the id when submitted which is great. But, what I want to do is pass the town name (key?) as well to display on the results page as well. I understand the best method is to use a hidden_field_tag with javascript to pass the value through, but all I can pass is the id value, not the town name value.
Form
<%= form_tag(results_path, method: :post) do %>
<%= select_tag :location, options_for_select(#locations) %>
<%= hidden_field_tag(:location_name, value = nil, html_options = {id: 'locationName'}) %>
<%= submit_tag 'Submit' %>
<% end %>
Javascript
$('#location').change(function(){
var input = document.getElementById("location");
var site = document.getElementById("locationName");
site.value = input.value;
})

As you're using jquery:
$('#location').change(function(){
var locationName = $("#location option:selected").text(); # this will return the selected option text e.g. location name
$("#locationName").val(locationName);
})
Hope it works!

Related

Ruby on Rails options_for_select onchange to call a Javascript function?

How do you setup a select element to change the maximum value of a number field element on a change of value?
I want to change the max value of the passenger number field when the flight ID is changed.
This is my code so far. As you can see, I added the onchange at the end of the select layout.
<div class="field">
<%= form.label :flight_id %>
<%= form.select :flight_id, options_for_select(Flight.all.map {|flight| [flight.name, flight.id]}, form.object.id), onchange: 'getMaxCapacity()' %>
</div>
<div class="field">
<% qty = #reservation.passengers %>
<%= form.label :passengers %>
<%= form.number_field :passengers, :id => 'passengers', min: 1, onchange: "calculateTotalPrice()", oninput: "calculateTotalPrice()" %>
</div>
My Javascript function getMaxCapacity() never gets entered. In the function I am setting the max value of the 'passengers' number field to the capacity variable.
<script type="text/javascript">
var capacity = {
<% Flight.all.each do |flight| %>
'<%= flight.id %>': <%= flight.capacity %>,
<% end %>
};
function getMaxCapacity() {
document.getElementById('passengers').max = capacity;
}
var costs = {
<% Flight.all.each do |flight| %>
'<%= flight.id %>': <%= flight.cost %>,
<% end %>
};
function calculateTotalPrice() {
var price = costs[document.getElementById('reservation_flight_id').value];
document.getElementById('cost').value = document.getElementById('passengers').value * price;
}
</script>
The signature of the FormBuilder#select looks like this:
select(method, choices = nil, options = {}, html_options = {}, &block)
This means html_options are the fourth parameter. Because you do not have any options for the select method you need to pass an empty hash as a third parameter.
<%= form.select(
:flight_id,
options_for_select(Flight.all.map {|flight| [flight.name, flight.id]}, form.object.id),
{}, # empty options
onchange: 'getMaxCapacity()' %>. # here the HTML options

How can I get the dynamic Id of nested form?

I got the following code, which I want to show the Add option button when the user chooses the OPTIONS type in the select box. It only works for the first time to add the question. I know the problem which is I gave the id to the select box, but if I do not do that, how can I get the dynamic id of the select box?
<%= f.fields_for :questions do |question_form| %>
<%= question_form.text_field :question_text %>
<%= question_form.select(:question_type, [ 'TEXT', 'OPTIONS', 'UPLOAD' ],{:prompt => 'Select One'}, :id => "my_id", :onchange => "myFunction()") %>
<%= question_form.link_to_remove "Remove this Question" %>
<%= question_form.fields_for :options do |option_form| %>
<%= option_form.text_field :option_text %>
<%= option_form.link_to_remove "Remove this option" %>
<% end %>
<p id = "test" hidden><%= question_form.link_to_add "Add a option", :options %></p>
<% end %>
<p><%= f.link_to_add "Add a Question", :questions %></p>
<p>
<%= f.submit %>
</p>
<% end %>
<script>
function myFunction(){
var e = document.getElementById("my_id");
var x = e.options[e.selectedIndex].value
if (x == "OPTIONS"){
document.getElementById("test").hidden = false;
}
else{
document.getElementById("test").hidden = true;
}
}
</script>
While I'm not entirely sure what you mean by "It only works for the first time to add the question", it sounds like you're confident that using document.getElementById() is the problem. (I don't know why it would be, but I'm unfamiliar with Rails, so I'll assume you're correct.)
If so, you can avoid that selector by using the target property of the EventListeners's built-in "event" parameter:
function myFunction(event){
`var x = event.target.options[e.target.selectedIndex].value`
...
(And you might be able to shorten this to event.target.value.)

select user and then dropdown of his challenges

A user has_many challenges.
When a user is selected...
<%= f.select :user_id, options_for_select(#challengers.collect { |challenger| [challenger.full_name] }) %>
... how can we show another dropdown with a list of his challenges?
<%= f.select :challenge_id, options_for_select(#challenger_challenges.collect { |challenged| [challenged.full_challenge]}) %>
In other words, how can we make "#challenger_challenges = the selected user's challenges"?
As it stand I get an error undefined method 'collect' for nil:NilClass since #challenger_challenges is nil.
OPTION 1
In challenges_controller I could do this:
#challengers = User.all
#challenger = User.find(params[:challenger_selected]) if (params[:challenger_selected]).present?
#challenger_challenges = #challenger.challenges
And then I would just need a way to refresh the page once a user is selected so that the user ID is passed in the params as :challenger_selected
OPTION 2
Achieve the aim of this question without the need of a page refresh. *Preferable
UPDATE
Based upon the comments below I realize I need to elaborate.
A user has_many challenges.
A user can create a duel.
In a duel there are two duelers.
The creator of the duel selects his own :challenge_id and then he selects the other dueler as well as one of his :challenge_id and then sets the #duel.consequence the dueler will have to do if he fails his challenge. The other dueler will get a duel request notification and then has the choice to accept or decline the conditions of the duel.
challenges.show.html.erb
<%= render 'duels/form' %>
duels/_form.html.erb
<%= simple_form_for(#duel) do |f| %>
<%= f.fields_for :duelers do |dueler| %>
<%= f.hidden_field :challenge_id, :value => #challenge.id %>
<%= #challenge.full_challenge %>
<% end %>
<%= f.fields_for :duelers do |dueler| %>
<%= render 'duels/dueler_fields', :f => dueler %>
<% end %>
<%= button_tag(type: 'submit', class: "btn", id: "challenge-create-save") do %>
Request Duel
<% end %>
<% end %>
duels/_dueler_fields.html.erb
<%= f.select :user_id, options_for_select(#challengers.collect { |challenger| [challenger.id] }) %>
# Trying to make this responsive to the user that is selected above
<%= render 'challenges/select', :f => f %>
<script>
$('#duel_duelers_attributes_1_user_id').change(function () {
var challenger_id = $(this).find(":selected").val();
var address = "<%= select_path %>".concat(challenger_id);
$.get(address, function(data) {
$("#duel_duelers_attributes_1_challenge_id").html(data);
});
});
</script>
routes
get 'challenges/select/:id' => 'challenges#select', as: 'select'
challenges/_select.html.erb
<%= f.select :challenge_id, options_for_select(#challenger_challenges.collect { |challenged| [challenged.full_challenge]}) %>
challenges_controller
def select
if (params[:challenger_id]).present?
#challenger = User.find(params[:challenger_id])
else
#challenger = User.find(1)
end
#challenger_challenges = #challenger.challenges
end
Credit for this should go to #Fallenhero - I am just explaining it in more detail.
You need to be able to identify the select tag.
<%= f.select ..., :html => {:id => :first} %>
You also need somewhere to put the second one.
<div id="second"></div>
Using jQuery:
$('#first').change(function () {
var challenger_id = $(this).find(":selected").val();
var address = "<%= [prints address to new select tag] %>".concat(challenger_id);
$.get(address, function(data) {
$("#second").html(data);
});
});
The address Ruby prints out should look something like challenges/select/ depending on how you want to design it. The / at the end is important.

How to save a JavaScript object as a hash record

I'm trying to save a hidden text field, which is a dynamically-created JavaScript object, as a hash record in the database. The problem is that the record is being saved with empty hash value. Here is the relevant code and errors from the trails I've made:
form code:
<%= form_for(#bill, remote: true) do |f| %>
<div class="hidden">
<%= f.text_field :items %>
<%= f.text_field :total_amount %>
<%= f.submit %>
</div>
<% end %>
JavaScript code:
// bill_items is the dynamically created object
var items = JSON.stringify(bill_items);
$('#bill_items').val(items); // Setting Input text value
$('#bill_total_amount').val(bill_total_amount);
$('form#new_bill').submit();
The params that are being passed:
Parameters: {"utf8"=>"✓",
"bill"=>{"items"=>"{\"bill_item_1\":{\"product\":\"vaseline 300 ml\",
\"unit_price\":\"215\",\"quantity\":\"1\",\"discount\":\"0.0\",
\"amount\":\"215\"}}", "total_amount"=>"215", "transaction_type"=>"Cash", "transaction_id"=>"some_id"}}
Controller code:
def create
#bill = Bill.new(bill_params)
if #rec_saved = #bill.save
respond_to do |f|
f.js
end
else
render 'new'
end
end
private
def bill_params
params.require(:bill).permit(:total_amount,
:transaction_type, :transaction_id, :items => {})
end
model code:
class Bill < ApplicationRecord
serialize :items, Hash
end
Using the debugger in the controller near bill_params method gives:
Unpermitted parameter: items
Return value is: nil
When creating a record from the console, it is working fine.
I searched and tried some suggestions but none of them worked. What am I doing wrong?
I think the issue is that items param has a string value, and you are permitting a hash.
First, if there are multiple objects in items, make it an array:
Parameters: {"utf8"=>"✓", "bill"=>{"items"=>"[{\"product\":\"name\",\"unit_price\":10},{\"product\":\"name2\",\"unit_price\":100}]", "total_amount"=>"215", "transaction_type"=>"Cash", "transaction_id"=>"some_id"}}
so that you can permit the keys of objects in the array:
private
def bill_params
params[:bill][:items] = JSON.parse(params[:bill][:items])
params.require(:bill).permit(
:total_amount, :transaction_type, :transaction_id, items: [:product, :unit_price]
)
end

JQuery How to hide/show dynamic number of divs all with unique id

I am not very good with JQuery but I am trying to learn. I am rendering number of "Milestone" number fields based on how many "Events" are defined in the database. So for 2 events there will be 2 number fields. What I am having trouble doing is hiding all the fields and only displaying one based on the selection in the "Event" select field. Here are the code snippets:
<div>
<%= f.label "Event" %>
<%= f.select(:event, options_for_select(get_events),{}, { :class => 'form-control', :id => 'event'})%>
<%if any_errors(#attendance_policy, :event) != nil%>
<%= any_errors(#attendance_policy, :event) %>
<%end%>
</div>
.....
<% Event.all.each do |event| %>
<div id='<%=event.event_name%>' >
<%= f.label "Absence Milestone(Make dynamic with selected event)"+event.event_name %>
<%= f.number_field :absence_milestone, in: 0..event.absence_max.to_i, class: 'form-control' %>
<%if any_errors(#attendance_policy, :absence_milestone) != nil%>
<%= any_errors(#attendance_policy, :absence_milestone) %>
<%end%>
</div>
<%end%>
Heres my pitiful attempt at JQuery:
$(document).ready(function() {
$("select#event").bind("change", function() {
var selected = $("select#event").text();
$("div#"+selected).show();
})
})
I understand I have to capture all the divs but I dont know how honestly... You cannot pass ruby arguments to JQuery... The hide them all, Capture text from event selector and only show one which id matches what is selected in the selector..
UPDATE
Working code:
Ruby portion not much changed other than me setting class of the div as 'wipe'.
<% Event.all.each do |event| %>
<div id="<%= event.event_name%>" class="wipe">
<%= f.label "Absence Milestone" %>
<%= f.number_field :absence_milestone, in: 0..event.absence_max.to_i, class: 'form-control' %>
<%if any_errors(#attendance_policy, :absence_milestone) != nil%>
<%= any_errors(#attendance_policy, :absence_milestone) %>
<%end%>
</div>
<%end%>
Here is updated jQuery. I have found another error while testing where my validator would complain that field cannot be blank even though I have entered a value in. Reason behind was that all other hidden fields did not have anything typed in. I updated jQuery to update ALL the hidden fields with value typed in the shown one on focus lost event.
jQuery Working(Might be messy):
$(document).ready(function() {
$("[class='wipe']").hide();
var selected = $("select#event").find("option:selected").text();
$("[id='" + selected + "']").show();
$("[id='" + selected + "']").on('focusout', function() {
var input = $(this).find("input").val();
$('input[type=number]').val(input)
})
$("select#event").on('change', function() {
$("[class='wipe']").hide();
var selected = $(this).find("option:selected").text();
$("[id='" + selected + "']").show();
$("[id='" + selected + "']").on('focusout', function() {
var input = $(this).find("input").val();
$('input[type=number]').val(input)
})
});
You're close. You should be using .change() instead of .bind() and you need to find the text of the selected option:
$(document).ready(function() {
$("select#event").change(function() {
var selected = $(this).find("option:selected").text();
$("div#"+selected).show();
})
})
.bind() is deprecated
FIDDLE
If I understood right .. You can't do that using Ids Id is unique so you need to use Classes
$("div."+selected)
you can use this code
$(document).ready(function() {
$('div.hidden').hide();
$("select#event").on('change',function() {
var selected = $(this).val();
$('div.hidden').hide();
$('div.'+selected).show()
});
});
you can check demo
DEMO

Categories