Dynamic select in nested form rails - javascript

How do js get the selected value in a dropdown and pass it to the controller so that it returns a list of names for the other dropdown?
What I've done so far:
salmonellas.js
$(function () {
$('body').on('change', "#mode_change", function () {
var selectedText = $(this).find("option:selected").text();
var selectedValue = $(this).val();
if (selectedText) {
$.get('/salmonellas/find_stages?mode_title='+ selectedText, function(selectedText) {
return $(selectedText).html();
});
}
});
});
salmonellas/form.html.erb
<div class="process_salmonellas">
<% f.simple_fields_for :process_salmonellas do |process_salmonella| %>
<%= render 'process_salmonella_fields', :f => process_salmonella %>
<% end %>
</div>
salmonellas/_process_salmonella_fields.html.erb
<div class="mode_change" id="mode_change">
<%= f.collection_select :title, Mode.order(:name), :id, :name, class: 'mode_change', id:'mode_change', include_blank: true, "data-content": :mode_id%>
</div>
<h4>Stage</h4>
<div class="stage">
<% f.simple_fields_for :stages do |stage| %>
<%= render 'stage_fields', :f => stage %>
<% end %>
</div>
salmonella/_stage_fields.html.erb
<div class="form-inputs">
<%= f.grouped_collection_select :title, Mode.order(:name), :steps, :name, :id, :name, class: "step_selection" %>
</div>
salmonellas_controller.rb
def find_stages
#mode = Mode.where("name = ?", params[:mode_title])
#steps = #mode.steps
end
Is looking for another model, why the fields have to be pre-registered. I'm using cocoon to let it nested.
Updating
salmonellas/_process_salmonella_fields.html.erb
<div class="form-inputs">
<%= f.collection_select :title, Mode.order(:name), :id, :name, class: 'mode_change', id:'mode_change', include_blank: true, "data-content": :mode_id%>
</div>
<h4>Stage</h4>
<div class="stage">
<% f.simple_fields_for :stages do |stage| %>
<%= render 'stage_fields', :f => stage %>
<% end %>
</div>
Updating 2
salmonellas/_process_salmonella_fields.html.erb
<div class="form-inputs">
<%= f.collection_select :title, Mode.order(:name), :id, :name, id:'mode_change', include_blank: true %>
</div>
salmonellas.js
$(function () {
$('body').on('change', ".mode_change", function () {
var selectedText = $(this).find("option:selected").text();
var selectedValue = $(this).val();
if (selectedText) {
$.get('/salmonellas/find_stages?mode_title='+ selectedText, function(selectedText) {
return $(selectedText).html();
});
}
});
});
Updating 3
salmonellas.js
$(function () {
$(document).on('change', "#mode_change", function () {
var selectedText = $(this).find("option:selected").text();
var selectedValue = $(this).val();
alert("Selected Text: " + selectedText);
});
});

IDs must be unique on your DOM. You are duplicating them for div and select tag. First change them and use this to get the value of selected option
$(document).on('change', ".mode_change", function () {
var selectedText = $(this).find("option:selected").text();
var selectedValue = $(this).val();
...

Related

Getting the individual checkbox value in JQuery

I have several checkboxes and have a JQuery function that I want to print out the value I give each checkbox when I click on the checkbox. However, 1 keeps printing out. I assign each checkbox an item.id based on a primary key from my db using Rails. Here is my code
<script>
$(document).ready(function(){
$('input[type="checkbox"]').on("change", function() {
var hall_id = $(this).val(); // here is where I want to get the value that I assigned to the checkbox
if (this.checked) {
console.log( hall_id );
} else {
console.log( hall_id );
}
});
});
</script>
<%= link_to "Logout", root_path %>
<h1>Hello <%= #user.first_name%> <%= #user.last_name%></h1>
<%= form_for #item do |f| %>
<%= f.label :to_do %>:
<%= f.text_field :to_do %><br />
<%= f.hidden_field :email, :value => #user.email%>
<%= f.submit %>
<% end %>
<% #items.each do |item|%>
<%if item.email == #user.email%>
<%= form_for #item do |f| %>
<%= item.id%>
<%= f.check_box :to_do, :value => item.id%> //This is where I assign the value for the check box
<%= item.to_do%><br />
<% end %>
<%end%>
<%end%>
In the image I am trying to print out the number by the checkbox(item.id), but in the console it only prints out 1
Look at the documentation on the check_box helper method: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
Notice that the optional 4th argument is the checked_value which defaults to 1. Here is how you can switch it to the id of your item object:
<%= f.check_box :to_do, :id, {}, item.id %>

undefined method `map' for :id:Symbol

ActionView::Template::Error (undefined method `map' for :id:Symbol):
1: <div id="dropdown-no-2">
2: <%= collection_select 'challenge_id', challenges, :id, :full_challenge, include_blank: true %>.
3: </div>
How can I solve this error so that only the challenges for that respective user are listed?
duels/_dueler_fields.html.erb
<%= f.select :user_id, User.order(:name).map { |user| [user.full_name, user.id] }, include_blank: true, id: "change-challenge-options" %>
will
<%= render :partial => 'user_challenges', locals: {challenges: Challenge.order(:created_at)} %>
<script>
$( "#change-challenge-options" ).change(function() {
$.ajax({
type: "GET",
url: '<%= user_challenges_path %>',
data: {name: $('#change-challenge-options').prop('value')}
});
});
</script>
duels/_user_challenges.html.erb
<div id="dropdown-no-2">
<%= collection_select(':challenge_id', challenges, :id, :full_challenge, include_blank: true) %>.
</div>
duels/user_challenges.html.erb
$("#dropdown-no-2").html('<%=j render :partial => "user_challenges", locals: {challenges: #challenges} %>');
duels_controller.rb
def user_challenges
#user = User.find(params[:id])
#challenges = #user.challenges.order(:created_at)
end
def new
#duel = Duel.new
#duel.duelers << Dueler.new(user_id: current_user.id, user_name: current_user.name, user_last_name: current_user.last_name)
respond_with(#duel)
end
routes.rb
get 'duels/user_challenges', :to => 'duels#user_challenges', as: 'user_challenges'
Change this to:
<%= collection_select(:duel, :challenge_id, challenges, :id, :full_challenge, include_blank: true) %>
Refer collection_select
Third parameter of collection_select has to be a collection (to populate the select), not a symbol.
http://apidock.com/rails/ActionView/Helpers/FormOptionsHelper/collection_select

AJAX function not getting called

I am new to RoR and AJAX, jquery etc. I am trying to make an ajax call in a view, but its not happening.
Corresponding controller(product_search_controller,rb) is:
def index
#products = querySolr(params[:q])
#productsProxy = Array.new
if #products != nil
#products.each do |p|
#productsProxy.push(ProductProxy.new(p))
end
else
#productProxy = []
end
#taxons = #productsProxy.map(&:get_taxonomy).compact.uniq
respond_with("Search Results") do |format|
format.js
format.html
format.xml { render :xml => #productsProxy, :only => [:name, :permalink, :description, :mrp], :methods => [:designer, :taxons, :price] }
end
end
Corresponding view(views/product_search/index.hrml.erb) is:
<%= render :partial => 'products', :locals => {:products => #productsProxy, :taxons => #taxons, :scope => self, :scope_type => "Search"} %>
<%= render :partial => 'shared/inf_scroll', :locals => {:url => "?&page=", :total_count => #total_count} %>
/views/product_search/_products.html.erb:
<% if products.empty? %>
<div class="not_found"><%= "No Products found for the selected query. Please try a different search." %></div>
<% elsif params.key?(:keywords) %>
<h3><%= t(:search_results, :keywords => h(params[:keywords])) %></h3>
<% end %>
<% if products.any? %>
<div class="product_rows">
<%= render :partial=> 'product_listing_feature', :locals => {:scope => scope, :scope_type => scope_type} %>
<div id="ql_product"></div>
<%taxons.each do |taxon|%>
<ul class="products" data-hook class="products">
<div class = "product_row">
<h1><%=taxon%></h1>
<% taxonProducts = Array.new %>
<% products.each do |product| %>
<%#ptaxon = product.get_taxonomy%>
<%if #ptaxon == taxon%>
<% taxonProducts.push(product) %>
<% end %>
<% end %>
<div class ="featured_product_list">
<ul class = "featured_products">
<div class = "page">
<%= render :partial=> 'product_listing', :locals=>{:collection=> taxonProducts} %>
</div>
</ul>
</div>
</div>
</ul>
<% end %>
</div>
</div>
<% end %>
i.e it renders another partial _product_listing which has the following script:
<script>
$("document").ready(function(){
$("li#product_<%=product.productId%>").hover(
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "visible");},
function(){$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");}
);
$("div#quick_look_<%=product.productId%>").css("visibility", "hidden");
});
hide_sold_out({
url: "<%= sold_out_status_taxons_url(#taxon) %>",
data: {
pids: "<%= collection.map(&:id).join(",") %>"
}
});
</script>
Helper:
var hide_sold_out = function(options){
$.ajax({
url: options["url"],
data: options["data"],
type: 'get',
dataType: 'text',
success: function(data){
pids = data.split(',');
for(var i = 0; i < pids.length; i++) {
if($("li#product_"+pids[i]).children("div.info").children("span.offer.sold").length == 0) {
$("li#product_"+pids[0]).children("div.info").append("<span class='offer sold'></div>");
$("li#product_"+pids[0]).children("div.info").children("div.product_listing_info_hover").children("div.listing_buttons").html("");
}
}
},
error: function(data){
console.log(data);
}
. I tried using the following in /views/product_search/index.js.erb:
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #productsProxy})) %></div></div>")
This didn't work. Then i tried:
<%#taxons.each do |taxon|%>
<%taxonProducts = Array.new%>
<%#productsProxy.each do |product|%>
<%#ptaxon=product.get_taxonomy%>
<%if #ptaxon==taxon%>
<%taxonProducts.push(product)%>
<%end%>
<%end%>
$("ul.products").append("<div class='page'><%= escape_javascript(render(:partial => 'product_listing', :locals=>{:collection=> #taxonProducts})) %></div></div>")
<%end%>
But the AJAX call is not doing what its supposed to do. Please could someone help me debug this. Thanks
These
url: options["url"],
data: options["data"],
should be
url: options.url,
data: options.data,

Complex Cascading Dropdown in Rails won't work in Edit Form

I recently tried to implement a cascading dropdown into my application with this tutorial on petermac.com: http://www.petermac.com/rails-3-jquery-and-multi-select-dependencies/
The tutorial basically talks about doing a cascading dropdown, where every dropdown box is an a separate partial and gets loaded with an jQuery onChange event when the parent select is changed.
Now I got this to work without a problem. But actually my select boxes have quite complicate relationships between them.
So, the form I belongs to a Model called AuditFunction and as the name says is for auditing. Every audit has a source and a target, which can be compared via several commands. The source as well as the target are selected via 3 select boxes. The first box selects the type of database the field is in. The second box selects the table and then the third box selects the field. As the field box can contain thousands of options I tried to implement the cascading dropdown to make it easier for the user to select the field.
To give you an overview, this is what my actions look like:
# new.html.erb
<%= simple_form_for #audit_function do |f| %>
<%= f.input :database_1, :as => :select, :collection => #databases, :include_blank => true %>
<%= render :partial => 'databases_1' %>
<%= render :partial => 'fields_1' %>
<%= f.input :database_2, :as => :select, :collection => #databases, :include_blank => true %>
<%= render :partial => 'databases_2' %>
<%= render :partial => 'fields_2' %>
<% end %>
The javascript for this looks like this:
# jQuery
<script type='text/javascript' charset='utf-8'>
jQuery(function($) {
// when the #country field changes
$("#audit_function_database_1").change(function() {
var database_1 = $('select#audit_function_database_1 :selected').val();
if(database_1 == "") database_1="0";
jQuery.get('/audit_functions/update_database_1_id_select/' + database_1, function(data){
$("#database_1_id").html(data);
})
return false;
});
})
</script>
<script type='text/javascript' charset='utf-8'>
jQuery(function($) {
// when the #country field changes
$("#audit_function_database_2").change(function() {
var database_2 = $('select#audit_function_database_2 :selected').val();
if(database_2 == "") database_2="0";
jQuery.get('/audit_functions/update_database_2_id_select/' + database_2, function(data){
$("#database_2_id").html(data);
})
return false;
});
})
Now I'm only going to show you the partials for database_1_id and field_1_id, but they look the same as database and field 2.
# _databases_1.html.erb
<script type="text/javascript">
jQuery(function($) {
$("#audit_function_database_1_id").change(function() {
var database_1_id = $('select#audit_function_database_1_id :selected').val();
if(database_1_id == "") database_1_id="0";
jQuery.get("/audit_functions/update_field_1_id_select/" + ("<%= params[:id] %>_" + database_1_id), function(data){
$("#field_1_id").html(data);
})
return false;
});
})
</script>
<%= simple_form_for "audit_function" do |f| %>
<% if params[:id] %>
<% if params[:id] == "imp" %>
<%= f.input :database_1_id, collection: AdOriTbl.all.order(ori_filename: :asc).collect{ |a| [a.ori_filename,a.id]} %>
<% elsif params[:id] == "ori" %>
<%= f.input :database_1_id, collection: AdOriTbl.all.order(otb_filename: :asc).collect{ |a| [a.otb_filename,a.id]} %>
<% elsif params[:id] == "mod" %>
<%= f.input :database_1_id, collection: AdQryMod.all.order(qry_mod_text: :asc).collect{ |a| [a.qry_mod_text,a.id]} %>
<% end %>
<% end %>
<% end %>
And now the file containing the target field.
# _fields_1.html.erb
<%= simple_form_for "audit_function" do |f| %>
<% if params[:id] %>
<% if params[:id].gsub(/_{1}\d{1,}\z/, "") == " mod " %>
<%= f.input :field_1_id, collection: AdQryFld.where(ad_qry_mod_id: params[:id].gsub(/\A\w{1,}_{1}/, "").to_i).order(order_id: :asc).collect{ |f| [f.qry_field_text,f.id]} %>
<% else %>
<%= f.input :field_1_id, collection: AdOriFld.where(ad_ori_tbl_id: params[:id].gsub(/\A\w{1,}_{1}/, "").to_i).order(id: :asc).collect{ |f| [f.otb_colhdg,f.id]} %>
<% end %>
<% end %>
<% end %>
The controller then contains all the actions triggered in the javascripts:
# audit_function_conroller.rb
def new
authorize! :new, :audit_functions
#audit_function = AuditFunction.new
#functions = [[I18n.t("text sum"),"sum"],[I18n.t("text quantity"),"quantity"],[I18n.t("text largest_value"),"largest_value"],[I18n.t("text smallest_value"),"smallest_value"]]
#databases = [[I18n.t("text original_database"),"imp"],[I18n.t("text archive_database"),"ori"],[I18n.t("text query_database"),"mod"]]
end
def update_database_1_id_select
if params[:id] == "mod"
type = "mod"
elsif params[:id] == "ori"
type = "ori"
elsif params[:id] == "imp"
type = "imp"
end
render partial: "databases_1", id: type
end
def update_field_1_id_select
type = params[:id]
render partial: "fields_1", id: type
end
Now, as messy as all of this looks, the good thing is that it gets the job done. And to clarify my MVC, these are the relations:
AdOriTbl has_many AdOriFlds
AdOriFld belongs_to AdOriTbl
AdQryMod has_many AdQryFlds
AdQryFld belongs_to AdQryMod
I hope the names don't bother you too much when reading this.
Now lets get back to the problem:
As I said this code works for creating a new object and everything is selected fine. But when I try to edit an object only the field with the database type (database_1 and database_2) are filled. The select boxes for the ID's of the databases are not rendered, while the boxes for the fields are. But all four ID fields are empty.
Now I already tried to fill the boxes by hand with a jQuery that basically looks similar to the ones I already have, but instead of getting triggered onChange, I trigger it when my audit_function has a database_id and render the select box and fill it with the value according value of database_id. This works as well.
The problem is that I can't do this with the field_id, because in the partial of database_1_id where the jQuery for the fields get triggered, I don't have the #audit_function object at hand and also it seems to interfere with the other javascripts.
Besides that I'd also like to think that there is a better way to do this, then my way. But I already tried other tutorials and ways and they either don't work when you don't have your straight-forward Country-State-City relationships or they don't work when editing.
So, any help would be really appreciated. Thanks!
I took the following tutorial as template to rewrite my cascading dropdown:
http://homeonrails.blogspot.de/2012/01/rails-31-linked-dropdown-cascading.html
So, now I throw all the different models into one array and filter it by appending names to the class, to differentiate not only by ID, but also by name. Also the jQuery Plugin chainedTo makes the code much more readable.
So, the controller looks now like this:
#types_for_dropdown = [[I18n.t("text archive_database"),"ori"],[I18n.t("text query_database"),"mod"]]
#tables_for_dropdown = []
#ad_qry_mods = AdQryMod.all
#ad_qry_mods.each do |i|
#tables_for_dropdown = #tables_for_dropdown << [i.qry_mod_text,"mod#{i.id}",{:class => "mod"}]
end
#ad_ori_tbls = AdOriTbl.all
#ad_ori_tbls.each do |i|
#tables_for_dropdown = #tables_for_dropdown << [i.otb_filename,"ori#{i.id}",{:class => "ori"}]
end
#fields_for_dropdown = []
#ad_qry_flds = AdQryFld.all
#ad_qry_flds.each do |i|
#fields_for_dropdown = #fields_for_dropdown << [i.qry_fieldname,i.id,{:class => "mod#{i.ad_qry_mod_id}"}]
end
#ad_ori_flds = AdOriFld.all
#ad_ori_flds.each do |i|
#fields_for_dropdown = #fields_for_dropdown << [i.otb_fieldname,i.id,{:class => "ori#{i.ad_ori_tbl_id}"}]
end
And the form looks like this:
<%= content_for :head do %>
<script>
$(document).ready(function(){
$('select#audit_function_database_1_id').chainedTo('select#audit_function_database_1');
$('select#audit_function_field_1_id').chainedTo('select#audit_function_database_1_id');
$('select#audit_function_database_2_id').chainedTo('select#audit_function_database_2');
$('select#audit_function_field_2_id').chainedTo('select#audit_function_database_2_id');
});
</script>
<% end %>
<div class="grid-6-12">
<%= f.input :database_1, label: I18n.t("field_label audit_function database_1"), hint: I18n.t("field_hint audit_function database_1"), as: :select, collection: #types_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_2, label: I18n.t("field_label audit_function database_2"), hint: I18n.t("field_hint audit_function database_2"), as: :select, collection: #types_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_1_id, label: I18n.t("field_label audit_function database_1_id"), hint: I18n.t("field_hint audit_function database_1_id"), as: :select, collection: #tables_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :database_2_id, label: I18n.t("field_label audit_function database_2_id"), hint: I18n.t("field_hint audit_function database_2_id"), as: :select, collection: #tables_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :field_1_id, label: I18n.t("field_label audit_function field_1_id"), hint: I18n.t("field_hint audit_function field_1_id"), as: :select, collection: #fields_for_dropdown, include_blank: true %>
</div>
<div class="grid-6-12">
<%= f.input :field_2_id, label: I18n.t("field_label audit_function field_2_id"), hint: I18n.t("field_hint audit_function field_2_id"), as: :select, collection: #fields_for_dropdown, include_blank: true %>
</div>
This is really a nice solution and I can recommend it to everyone!

Enable/disable nested form fields with javascript

I have a nested form with checkboxes and text fields. I would like to be able to have the text fields only be enabled if the text box for that specific nested form is clicked/enabled. It is currently hard coded to enable/disable fields if the "custom" text box is set. How can I have javascript update these textbox attributes on the fly?
Form.erb now
<%= simple_nested_form_for #client do |f| %>
<%= f.fields_for :client_prices do |def_price_form| %>
<div class="controls controls-row">
<div class='span10'>
<% if def_price_form.object.custom == true %>
<%= def_price_form.input :custom, :wrapper_html => { :class => 'span1' } %>
<% end %>
<%= def_price_form.input :visit_type, :wrapper_html => { :class => 'span2' } %>
<%= def_price_form.input :price, :wrapper => :prepend, :wrapper_html => { :class => 'span2' }, :label => "Price" do %>
<%= content_tag :span, "$", :class => "add-on" %>
<%= def_price_form.input_field :price %>
<%= def_price_form.link_to_remove '<i class="icon-remove"></i>'.html_safe, :class => 'btn btn-danger', :wrapper_html => { :class => 'span3 pull-left' } %>
<%end%>
<% else %>
<%= def_price_form.input :custom, :hidden => false, :wrapper_html => { :class => 'span1' } %>
<%= def_price_form.input :visit_type, disabled: true, :wrapper_html => { :class => 'span2' } %>
<%= def_price_form.input :price, :wrapper => :prepend, :wrapper_html => { :class => 'span2' }, :label => "Price" do %>
<%= content_tag :span, "$", :class => "add-on" %>
<%= def_price_form.input_field :price, disabled: true %>
<%end%>
<%end%>
</div>
</div>
<% end %>
<%= f.link_to_add "Add a custom price", :client_prices, :class => 'btn btn-success' %>
<p> </p>
<div class="controls">
<%= f.button :submit, :class => 'btn btn-primary' %>
</div>
<% end %>
HTML generated by RoR here
http://jsfiddle.net/59AXJ/
This gets the attribute name from the checkbox that is clicked. Then finds inputs that have similar names, those are the inputs that we will toggle "disabled".
$("input[type='checkbox']").click(function () {
var thisCheckbox = $(this);
var id = $(this).attr("id");
var text = $("label[for=" + id + "]").text().toLowerCase();
var name = $(this).attr("name").replace("[" + text + "]", "");
$("input[name*='" + name + "']").each(function () {
var thisInput = $(this);
if (thisInput.attr("disabled")) {
thisInput.removeAttr("disabled");
} else {
thisInput.attr("disabled", "disabled");
thisCheckbox.removeAttr("disabled");
}
})
});
http://jsfiddle.net/Sbw65/ <-- test it out
As I know, it's impossible to make this on fly, but you can write some unique function on javascript, wich will connect some input with some checkbox by their css class. Something like this (code on CoffeeScript):
changeCheckbox: (class_value) =>
$('[type=checkbox] '+class_value)). on 'check', (e) ->
$input = $(e.currentTarget)
if !$input.prop("checked")
$("input "+class_value).prop('disabled', false)
else
$("input "+class_value).prop('disabled', true)
After that, you just need to add some class for connected checkbox and inputs.

Categories