I'm using the ancestry gem in order to create categories and subcategories(parent, child, sibling). Then I have a select input inside a simple form:
<div class="form-group">
<%= f.input :parent_category_id, collection: #categories, label: "Category", as: :grouped_select, group_method: :children, include_blank: true, input_html: { id: 'first-dropdown' } %>
</div>
I populate the above input with the parent categories:
#categories = Category.where(ancestry: nil)
And when I select a category in the above input the subcategories appear in the input below. If the category has no subcategories then the input is empty.
<div class="form-group">
<%= f.input :category_id, label: "Subcategories", :collection => [], :label_method => :name, :value_method => :id, required: true, input_html: { multiple: true, id: 'second-dropdown' } %>
</div>
$('#first-dropdown').on('change', function() {
$.ajax({
url: 'categories/select_item?category_id=' + $(this).val(),
dataType: 'json',
success: function(data) {
let childElement = $('#second-dropdown');
childElement.html('');
data.forEach(function(v) {
let id = v.id;
let name = v.name;
childElement.append('<option value="' + id + '">' + name + '</option>');
});
}
});
});
Everything works just fine with this setup. But now I would like to add a feature which I don't know how to. I want the second input to be initially hidden. And I want to show the second input if subcategories exist and hide the second input if subcategories don't exist. Any ideas how to implement this?
this could work...
success: function(data) {
let childElement = $('#second-dropdown');
childElement.toggle(Array.isArray(data) && data.length > 0)
...
Related
For some time now, I'm trying to generate a reservation form, where only available rooms are listed for the arrival and departure dates chosen in that same reservation form. Unfortunately, until now I didn't manage to do so.
I set out a question already on my previous attempt, without any success. => https://stackoverflow.com/posts/59083421/edit
I'm now trying to look for alternative ways to get there. For reference, please find my previous attempt below.
Previous attempt: general idea
Tried to send/receive an AJAX. Cannot reach the success stage, and the bug seem lie in the dataType the AJAX call is expecting/I'm sending (JS vs JSON). Unfortunately, I don't know how to solve this.
When I use format.js in my controller, I do not reach the success stage in my ajax call
when I use render json: {:rooms => #rooms} I do not reach my hotels/rooms_availability.js.erb file and subsequently am not able to insert my available rooms.
Previous attempt: code
reservations/new.html.erb
<%= simple_form_for [#hotel, #reservation] do |f|%>
<div class="col col-sm-3">
<%= f.input :arrival,
as: :string,
label:false,
placeholder: "From",
wrapper_html: { class: "inline_field_wrapper" },
input_html:{ id: "start_date"} %>
</div>
<div class="col col-sm-3">
<%= f.input :departure,
as: :string,
label:false,
placeholder: "From",
wrapper_html: { class: "inline_field_wrapper" },
input_html:{ id: "end_date"} %>
</div>
<div class="col col-sm-4">
<%= f.input :room_id, collection: #rooms %>
</div>
<%= f.button :submit, "Search", class: "create-reservation-btn"%>
<% end %>
script for reservations/new.html.erb
<script>
const checkIn = document.querySelector('#start_date');
const checkOut = document.querySelector('#end_date');
const checkInAndOut = [checkIn, checkOut];
checkInAndOut.forEach((item) => {
item.addEventListener('change', (event) => {
if ((checkIn.value.length > 0) && (checkOut.value.length > 0)){
checkAvailability();
}
})
})
function checkAvailability(){
$.ajax({
url: "<%= rooms_availability_hotel_path(#hotel) %>" ,
dataType: 'json',
type: "POST",
data: `arrival=${start_date.value}&departure=${end_date.value}`,
success: function(data) {
console.log('succes')
console.log(data);
},
error: function(response) {
console.log('failure')
console.log(response);
}
});
};
</script>
hotels_controller
def rooms_availability
hotel = Hotel.includes(:rooms).find(params[:id])
arrival = Date.parse room_params[:arrival]
departure = Date.parse room_params[:departure]
time_span = arrival..departure
#unavailable_rooms = Room.joins(:reservations).where(reservations: {hotel: hotel}).where("reservations.arrival <= ? AND ? >= reservations.departure", arrival, departure).distinct
#hotel_cats = hotel.room_categories
#hotel_rooms = Room.where(room_category: hotel_cats)
#rooms = hotel_rooms - #unavailable_rooms
render json: {:rooms => #rooms}
#respond_to do |format|
#format.js
#end
end
def room_params
params.permit(:arrival, :departure, :format, :id)
end
hotels/rooms_availability.js.erb
var selectList = document.getElementById('reservation_room_id')
function empty() {
selectList.innerHTML = "";
}
empty();
<% unless #rooms.empty? %>
<% #rooms.each do |room|%>
selectList.insertAdjacentHTML('beforeend', '<option value="<%= room.id %>"><%= room.name %></option>');
<% end %>
<% end %>
I have Rails 5.2.3 and I use the ancestry gem.
I want a user to create an offer for an automotive part, but in the new form, I want to be able to choose the category/subcategory that the part belongs to, and then to fill in the other details that I have, and then submit the form to create the offer. Let's say that someone wants to sell Brake Pads.
So first has to select the Category/Subcategory and so on...
(So when he choose Car, then the second dropdown should show the subcategories for the Car)
E.g:
Dropdown1: CarDropdown2: Brakes
So after choosing Brakes, he can fill in the other fields and submit.
What I have:
I have already created the Category/Subcategory in the console just to make it work:
Eg
car = Category.create!(name: "Car")
brakes = Category.create!(name: "Brakes", parent: car)
#category.rb
class Category < ApplicationRecord
has_ancestry cache_depth: true
has_many :parts
end
#part.rb
class Part < ApplicationRecord
belongs_to :category
end
#categories_controller.rb
class CategoriesController < ApplicationController
def select_item
category = #category.find(params[:category_id])
render json: category.children
end
end
#app/inputs/fake_select_input.rb
class FakeSelectInput < SimpleForm::Inputs::CollectionSelectInput
def input(wrapper_options = nil)
label_method, value_method = detect_collection_methods
merged_input_options =
merge_wrapper_options(input_html_options,
wrapper_options).merge(input_options.slice(:multiple,
:include_blank, :disabled, :prompt))
template.select_tag(
attribute_name,
template.options_from_collection_for_select(collection,
value_method, label_method, selected:
input_options[:selected], disabled:
input_options[:disabled]),
merged_input_options
)
end
end
#routes.rb
Rails.application.routes.draw do
resources :parts
resources :categories, only: [] do
get :select_item, on: :collection
end
end
#application.js
$('#first-dropdown').on('change', function() {
$.ajax({
url: 'categories/select_item?category_id=' + $(this).val(),
dataType: 'json',
success: function(data) {
var childElement = $('#second-dropdown');
childElement.html('');
data.forEach(function(v) {
var id = v.id;
console.log(id);
var name = v.name;
childElement.append('<option value="' + id + '">' + name + '</option>');
});
}
});
});
#views/parts/new.html.haml
= simple_form_for #part do |f|
= f.input :parent_category_id, as: :fake_select, collection: Category.roots, input_html: { id: 'first-dropdown' }, label: "Category"
= f.input :category_id, collection: [], input_html: { id: 'second-dropdown' }, label: "Subcategory"
= f.input :title
= f.input :part_number
= f.input :price, label: "Price"
= f.input :condition, label: "Condition", prompt: "-", collection:([["New", "New"], ["Used", "Used"], ["Rebuilt", "Rebuilt"], ["Aftermarket/Imitation", "Aftermarket/Imitation"]])
= f.input :make, label: "Part Make"
= f.input :part_model_name, label: "Part Model"
= f.input :description
.form-group
= f.button :submit, class: "btn btn-primary btn-block"
The thing is that the Dropdown1 has the Category "Car", and the Dropdown2 is always empty, and ofc I have no errors (I am using ancestry because later I will add many categories / subcategories / subsubcategories etc)
The problem: image of my dropdowns (When I open the second is empty)
I'm trying to populate one drop down list based on the selection of another drop down list in my rails project. The only difference is that both drop down lists should be populated from one model.
The model is City, and it has name and state.
name is the city name, and state is the state to which the city belongs.
For example, a city object would be :
id = 1
name = LOSANGELES
state = CA
I've checked Rails 4: How to update a collection_select based on another collection_select through AJAX?
and other links but I can't seem to figure out how to populate the city drop down list from the same Model as the first dropdown
Here's my code :
controllers/city_stats_controller.rb :
def city_stats
#state = params[:state]
#cities = City.select(:name).all.where(:state => state)
respond_to do |format|
format.json { render :json => #cities }
end
end
views/city_stats/city_stats.html.erb :
<div class="row">
<label>State <span>*</span></label>
<%= collection_select :city, :state, City.select(:state).uniq.order('state ASC'), :id, :state, {:prompt => 'Select a State'}, {id: 'state', multiple: false} %>
<label>City <span>*</span></label>
<%= collection_select :city, :name, [], :id, :name, {:prompt => 'Select a City'}, {id: 'name', multiple: false} %>
</div>
<script type="text/javascript">
$(document).ready(function() {
$("#state").on('change', function(){
$.ajax({
url: "/admin/city_stats",
type: "GET",
data: {state: $(this).val()},
success: function(data) {
$("#city").children().remove();
// Create options and append to the list
var listitems = [];
$.each(data,function(key, value) {
listitems += '<option value="' + key+ '">' + value + '</option>'; });
$("#city").append(listitems);
console.log(listitems);
}
})
});
});
</script>
Any help is much appreciated!
change your city_stats method like. This method should return id and name
def city_stats
#state = params[:state]
#cities = City.where(:state => state).select(:id, :name)
respond_to do |format|
format.json { render :json => #cities }
end
end
Change your each function in ajax call like this.Since data in response is array of object we are using value.id, value.name .
$.each(data,function(key, value) {
listitems += '<option value="' + value.id + '">' + value.name + '</option>';
});
I am trying to implement a ajax dropdown on a rails app. When I select the category, the sub category drop down should populate the sub categories according to the category selected. Currently the sub category drop down is getting populated only when I select the category and enter "filter" and goes to the next page. I have the controller method as follows:
controller
def index
#categories = Category.roots.active.all
if (params.keys & ['category_id', 'sub_category_id']).present?
if params[:category_id].present?
#category = Category.active.find params[:category_id]
else
#category = Category.active.find params[:sub_category_id] if params[:sub_category_id].present?
end
end
#root_categories = Category.active.roots
#sub_categories = #category.children.active if params[:category_id].present?
#sub_categories ||= {}
#wanted_equipments = WantedEquipment.Approved.filter(params.slice(:category_id, :sub_category_id)).order("created_at desc").page(params[:page]).per(per_page_items)
end
def fetch_sub_categories
category = Category.active.where(id: params[:category_id].to_i).first
sub_categories = category.present? ? category.children.active : []
render json: sub_categories, status: 200
end
This is the js file
equipment.js
$(document).ready(function($) {
// Fetch sub-categories as per category selected
$("select#category_id, select#wanted_equipment_category_id").selectric().change(function(e){
$.getJSON("/fetch_sub_categories",{category_id: $(this).val(), ajax: 'true'}, function(response){
var options = '';
for (var i = 0; i < response.length; i++) {
options += '<option value="' + response[i].id + '">' + response[i].name + '</option>';
}
if (e.target.id=="category_id"){
$("select#sub_category").html('<option value="">Sub-Category</option>'+options);
var Selectric = $('select#sub_category').data('selectric');
Selectric.init();
}
if (e.target.id=="wanted_equipment_category_id"){
$("select#wanted_equipment_sub_category_id").html('<option value="">Select Sub-Category</option>'+options);
var Selectric = $('select#wanted_equipment_sub_category_id').data('selectric');
Selectric.init();
}
})
})
$(document).ajaxStop(function () {
$('.loader').hide();
});
$(document).ajaxStart(function () {
$('.loader').show();
});
});
This is the index.html.erb file
<%= form_tag filter_wanted_equipments_path, :method => 'get' do %>
<%= select_tag "category_id", options_from_collection_for_select(#categories, "id", "name", params[:category_id]), :prompt=>"Select Category", id: "search_category" %>
<%= select_tag "sub_category_id", options_from_collection_for_select(#sub_categories, "id", "name", params[:sub_category_id]), :prompt=>"Sub-Category" %>
<%= hidden_field_tag( 'category_id', params[:category_id]) if params[:category_id].present? %>
<%= hidden_field_tag( 'sub_category_id', params[:sub_category_id]) if params[:sub_category_id].present? %>
<%= submit_tag "filter-", :name => nil, style: "display:none;", id: 'filter-submit' %>
<% end %>
The routes.rb file
resources :wanted_equipments do
get "/fetch_sub_categories" => 'wanted_equipments#fetch_sub_categories'
collection do
get 'search'
get 'filter'
end
end
http://blog.ashwani.co.in/new/2017/03/06/How-to-use-create-ajax-dropdown-from-database-models-in-Rails.html
Code:
index.html.erb
<div>
<%= f.collection_select :vertical, #verticals, :vertical, :vertical, {:prompt => "Select a Vertical"}, {:class => "dropdown_vertical btn btn-default dropdown-toggle"} %>
<%= f.collection_select :subVertical, #subVerticals, :subVertical, :subVertical, {:prompt => "Select a Sub Vertical"}, {:class => "dropdown_subVertical btn btn-default dropdown-toggle"} %>
</div>
custom.js
$("#search_vertical").on('change', function(){ var listitems = []; $.ajax({ url: "populate_subVerticals", type: "GET", data: {vertical_name: $(this).val()}, success: function(data) { $("#search_subVertical").children().remove(); $("#search_subVertical").append('<option value=>' + "Select a Sub Vertical" + '</option>'); $.each(data,function(key, value) { listitems += '<option value="' + value.subVertical + '">' + value.subVertical + '</option>'; }); $("#search_subVertical").append(listitems); } }) });
Controller
def populate_subVerticals vertical_name = params[:vertical_name] #verticals = Vertical.where(:vertical => vertical_name).select("id","subVertical").all respond_to do |format| format.json { render json: #verticals } end end
routes.rb file
'populate_subVerticals', to: 'verticals#populate_subVerticals'
Here is a piece of code what I have used for populating dynamic drop-down.
index.html.erb --> dd1_id is the static drop-down, once dd1_id is selected, dd2_id drop-down will be populated.
<tr>
<td class="td1"></td>
<td class="td2"><span class="">Drop Down 1:</span></td>
<td><%=f.select :dd1_id, options_for_select(#abc.collect { |abc| [abc.type_name.upcase, abc.type_name.upcase] }, 0), {prompt: "-- Select --"}, { id: 'dd_1_select',:style => "width:300px"} %></td>
</tr>
<tr>
<td class="td1"></td>
<td class="td2"><span class="">Drop Down 2:</span></td>
<td><%=f.select :dd2_id, options_for_select([""]), {}, {:id => "dd_2_select",:style => "width:300px;"} %></td>
</tr>
device.js --> It has a onchange function that checks if the dd1_id drop-down is selected with a value and then triggers a function called update_dd2, that captures the dd1_id value and hits the url specified below in the ajax request.
$('#dd_1_select').on('change', function(){
if ($("#dd_1_select option:selected").val() != ""){
update_dd2();
$('#dd_2_select').val('');
}
});
function update_dd2() {
$.ajax({
url: '/update_dd_2',
data: {
dd1_value: $("#dd_1_select option:selected").val()
},
method: 'GET',
dataType: 'script',
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))},
success: function(){
console.log("Dynamic dd_2 select OK!");
$('#dd_2_select').prop('disabled',false);
},
failure: function(error){
console.log("AJAX FAILURE: "+error);
alert("Something went wrong, Please try again later.");
},
error: function(error){
console.log("AJAX ERROR: "+error);
alert("Oops! there was an error, Please reload the page and try again.");
}
});
}
}
routes.rb --> The url specified in the ajax request would be redirected to an action
get "update_dd_2" => "abc#update_dd_2", :as => "update_dd_2"
Controller/Action --> Based on the value selected from the first drop-down, It fetches the data required to populate the second drop-down
def update_dd_2
#values = SomeTable.where("id in (?)", params[:dd1_value])
respond_to do |type|
type.js
end
end
dd1_value.js --> The above action would expect a .js file in views
This would render a partial response to the html file and the drop-down would be populated with the appropriate values
$("#dd_2_select").empty().append("<%= escape_javascript(render(:partial => #values )) %>");
Hello guys i am trying attempt a dynamic select here. as soon as i select the customer his total value in the bill should come and get displayed in the text field tag.
the view
jQuery(document).ready(function(){
jQuery(".customerid").bind("change", function() {
var data = {
customer_id: jQuery(".customerid :selected").val()
}
jQuery.ajax({
url: "get_cust_bill",
type: 'GET',
dataType: 'script',
data: data
});
});
});
</script>
<div class ="customerid"><%= f.label :customer_id %>
<%= f.collection_select :customer_id, Customer.all, :id, :name, options ={:prompt => "-Select a Customer"}, :class => "state", :style=>'width:210px;'%></div><br />
<div class ="customerbill">
<%= f.label :total_value, "Total Value" %>
<%= render :partial => "customerbill" %>
js.erb file
jQuery('.customerbill').html("<%= escape_javascript(render :partial => 'customerbill') %>");
the customerbill partial
<% options = []
options = #cust_bill.total_value if #cust_bill.present? %>
<%= text_field_tag "total_value", options %>
in contoller
def get_cust_bill
#cust_bill = CustomerBill.find_all_by_customer_id(params[:customer_id]) if params[:customer_id]
end
I feel the problem lies in the partial, the way i am calling the options so can anyone guide me how to get the value in text field??? thank in advance.
From what I understand, total_value text field does not show anything. Could you try to output the value of options and check if it always has a value? I suggest you check out the documentation for the text_field_tag. Basically, it accepts three variables like this:
text_field_tag(name, value = nil, options = {})
i was using getJSON method....and i feel that can be used here. hope the followng works.
jQuery(document).ready(function()
{
jQuery(".customerid select").bind("change", function() {
var data = {
product_id: jQuery(this).val()
}
jQuery.getJSON(
"/controller_name/get_cust_bill",
data,
function(data){
var result = "";
res = parseFloat(a[1]);
jQuery('.price input').val(res);
});
});
});
controller
def get_cust_bill
#cust_bill = CustomerBill.find_all_by_customer_id(params[:customer_id]).map{|p| [p.price]} if params[:customer_id]
respond_to do |format|
format.json { render json: #cust_bill }
end
end
so no need of calling js. erb partial you can simply have
<div class = "price"><%= f.input :price, :label => 'Price', :input_html => { :size => 20} %></div><br/>
all the best :)