Update checkbox options using ajax in Rails 5 - javascript

A little explanation of the app. It's a tour registration system for a multi-campus organization. Someone should be able to come in and select a campus from a select box and have the "options" checkboxes and "tour dates" radio buttons update to be campus specific.
I've got the script triggering when someone changes the select box but it keeps returning a 404 when I go to the path and the url looks really wonky. Also I know I'm going to run into trouble when I try to .html replace the section with new options. Ok without further ado, here's the code. Any guidance would be appreciated!
_form.html.erb
...
<div class="field">
<%= label_tag 'Campus' %>
<%= select_tag 'campuses', options_from_collection_for_select(#churches, 'id', 'name', selected: (#registration.event.church.id unless #registration.event.nil?) )%>
</div>
<div class="field">
<%= label_tag 'Areas of Interest' %>
<div id="options_container">
<%= f.collection_check_boxes :option_ids, #options, :id, :ministry_area do |b| %>
<div class="collection-check-box">
<%= b.check_box %>
<%= b.label %>
</div>
<% end %>
</div>
</div>
<div class="field">
<%= label_tag 'Tour Dates' %>
<div id="events_container">
<%= f.collection_radio_buttons(:event_id, #events, :id, :event_datetime) do |b| %>
<div class="radio">
<%= b.radio_button + " " + b.label %>
</div>
<% end %>
</div>
</div>
<div class="actions">
<%= f.submit params[:action] == 'edit' ? "Update Registration" : "Register", class: 'button' %>
</div>
<% end %>
<script>
$(document).ready(function () {
$('#campuses').change(function () {
$.ajax({
url: "<%= update_campus_options_and_events_path %>",
data: {
campus_id: $('#campuses').val()
},
dataType: "script"
});
});
});
</script>
routes.rb
Rails.application.routes.draw do
resources :registrations
root 'registrations#index'
get 'update_campus_options_and_events', to: 'registrations#update_campus_options_and_events'
end
registrations_controller.rb
...
def update_campus_options_and_events
#events = Event.find(params[:campus_id])
#options = Option.find(params[:campus_id])
respond_to do |format|
format.html
format.js {}
end
end
...
update_campus_options_and_dates.js.erb
console.log('Options changed via ajax');
$('#options_container').html("<%= escape_javascript(<%= f.collection_check_boxes :option_ids, #options, :id, :ministry_area do |b| %>) %>");
$('#events_container').html("<%= escape_javascript(<%= f.collection_radio_buttons(:event_id, #events, :id, :event_datetime) do |b| %>) %>");

Related

Rails + Javascript: Create one parent model and multiple child model in same time

I have a parent model (paper) and a nested child model (tape) and want to create multiple child with a parent in same time without using any gems.
The input fields of tape should be dynamically added through clicking “+”.
If I write “3.times { #paper.tapes.build }” in controller, I can create 1 paper and 3 tapes in same time.
But if how many times the input field should be added is depend on the user (if user click "+" 10 times, 1 parent model and 10 child model should be saved in one time), how should I modify the code?
Here is my codes.
Paper Model
has_many :tapes
accepts_nested_attributes_for :tapes, allow_destroy: true
Tape Model
belongs_to :paper, optional: true
Controller
def new
#paper = Paper.new
3.times { #paper.tapes.build }
end
def create
#paper = Paper.new(paper_params)
#paper.user_id = current_user.id
if #paper.save
redirect_to action_list_paper_path(#paper.id)
else
render 'new'
end
end
Viewer
<%= nested_form_for(#paper) do |f| %>
<div class="container">
<%= stylesheet_link_tag 'papers', media: 'all', 'data-turbolinks-track': 'reload' %>
<div class= "paper_form">
<div class="col-md-6">
<%= f.label(:content, "Name") %>
<%= f.text_area :content %>
</div>
</div>
</div>
<div class="tape_form">
<%= f.fields_for :tapes do |tape| %>
<div id="input_pluralBox">
<div id="input_plural">
<div class="col-md-4">
<%= tape.label :label %>
<%= tape.text_field :label %>
</div>
</div>
<input type="button" value="+" class="add pluralBtn">
<input type="button" value="-" class="del pluralBtn">
</div>
</div>
<% end %>
</div>
</div>
<% end %>
Javascript (The input column “label” will be added with "+" through javascript).
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).on("click", ".add", function() {
$(this).parent().clone(true).insertAfter($(this).parent());
});
$(document).on("click", ".del", function() {
var target = $(this).parent();
if (target.parent().children().length > 1) {
target.remove();
}
});
</script>
An example of how to add nested records in a form:
<%= form.fields_for :headers, get_headers(client) do |builder| %>
<div>
<div class="header-fields form-row">
<%= builder.hidden_field :id %>
<div class="form-group col col-md-4">
<%= builder.label :key %>
<%= builder.text_field :key, class: 'form-control' %>
</div>
<div class="form-group col col-md-6">
<%= builder.label :value %>
<%= builder.text_field :value, class: 'form-control', value: builder.object.value %>
</div>
<% if action_name == "edit" %>
<div class="form-group col col-md-2">
<div class="form-check">
<%= builder.check_box :_destroy, class: 'form-check-input' %>
<%= builder.label :_destroy, "Destroy?", class: 'form-check-label' %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
Helper function
def get_headers(client)
return client.headers if client.headers.any?
[Header.new]
end
Controller params
def client_params
params.require(:client).permit(headers_attributes: [:id, :key, :value, :_destroy])
end
Model:
class Client < ApplicationRecord
has_many :headers, dependent: :destroy
accepts_nested_attributes_for :headers, allow_destroy: true
end
Then JS as required for adding / removing rows.

How to display validation error in rails using AJAX

I need to display the validation error of my post model. I have used AJAX call to create a post into the index page of the post. So that when the NewPost button is clicked it will display the new post form partial into the index page. While creating the post in index page if there is any validation errors found, the errors are displayed and it renders the new post form partial in js format again so that the new post form appears twice along with the validation error.
Posts controller:
def create
#post = #topic.posts.build(post_params)
#post.user = current_user
respond_to do |format|
if #post.save
# Success
else
format.js { render 'posts/new' }
end
end
end
Create.js.erb file:
alert("Post created Successfully");
$('.new_post').hide();
$('.new_one').show();
$('.post_div').prepend('<%= j render #post %>');
Index.html.erb file:
<div class="container" >
<% if params[:topic_id].present? %>
<h2 align="center"><span class="em-text"><%= #topic.topicname %> Posts</span></h2><hr>
<%= link_to "New Post", new_topic_post_path, :class => 'btn btn-primary new_one' ,remote: true%> <br><br><br>
<% else %>
<h2 align="center"><span class="em-text">All Posts</span></h2><hr>
<% end %>
<div class="post_div">
<%= render #posts %>
</div>
<%= will_paginate #posts, renderer: BootstrapPagination::Rails %>
</div>
Post partial for new post form:
<%= form_for [#topic, #post],remote: true,html: {multipart: true}, url: topic_posts_path do |f| %>
<% if #post.errors.any? %>
<% #post.errors.full_messages.each do |msg| %>
<div class="alert alert-danger"><%= msg %></div>
<% end %>
<% end %>
<div class="form-group">
<%= f.label "Title" %><br/>
<%= f.text_field(:title,{:class => 'form-control', :placeholder => 'Enter the Title'}) %>
</div>
<div class="form-group">
<%= f.label "Body" %><br/>
<%= f.text_area(:body, {:class => 'form-control', :placeholder => 'Enter the Post Body'}) %>
</div>
<div class="form-group">
<%= f.submit({:class => 'btn btn-primary'})%>
</div>
<% end %>
new.js.erb file:
$('.new_one').hide().after("<%= j render 'form' %>")
Use can like this
<% if #post.errors.any? %>
alert("ERROR(S):\n<%= j #post.errors.full_messages.join("\n") %>")
Check the post whether it has any errors if error exists alert the error else do something

Saving Nested Data Before Parent is Assigned an ID

I have a Resume model and an Education model. Education belongs_to resume and resume has_many educations.
I'm currently using a form in Resume's show.html.erb view to enter data for educations just to make sure it works.
In my routes.rb file I have:
resources :resumes do
resources :educations
end
In my educations_controller.rb file I have this:
def create
#resume = Resume.find(params[:resume_id])
#education = #resume.educations.build(education_params)
respond_to do |format|
if #education.save
format.html { redirect_to #resume, notice: 'Education was successfully created.' }
format.json { render :show, status: :created, location: #education }
else
format.html { render :new }
format.json { render json: #education.errors, status: :unprocessable_entity }
end
end
end
This allows me, in my views/resumes/show.html.erbto have the following:
<%= form_for [#resume,Education.new] do |f| %>
<div class="field">
<%= f.label :sectionTitle %><br>
<%= f.text_field :sectionTitle %>
</div>
<div class="field">
<%= f.label :completed %><br>
<%= f.date_select :completed %>
</div>
<div class="field">
<%= f.label :degree %><br>
<%= f.text_field :degree %>
</div>
<div class="field">
<%= f.label :school %><br>
<%= f.text_field :school %>
</div>
<div class="field">
<%= f.label :summary %><br>
<%= f.text_area :summary %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
This is currently working and allows me to enter multiple educations per Resume.
The issue is, I first have to create the resume entry before creating an education entry because the education entry depends on the resume_id integer.
How can I re structure my code so that I can create multiple education entries for a specific resume that doesn't yet have an ID so that essentially, on submit the resume is assigned an ID then any subsequent educations are attached to the given resume_id and given their own education ID?
I suspect I'll probably have to use javascript which is fine, but even so, I'm not sure what to do once intercept the default form action.
This is just little example but it works totally fine.
In routes.rb
post 'add_resume_education' => 'resumes#twince'
In resumes_controller.rb, in your case. Use your own MODEL like resume and education and change passing params too.
def twince
resume = Resume.create!(title: params[:data][:category_title])
post = resume.educations.create!(sectionTitle: params[:data][:educations][:sectionTitle])
redirect_to :back, notice: 'Yeah Created'
end
in HTML page:
<%= form_for :data, url: add_resume_education_path do |f| %>
<div class="field">
<%= f.label :category_title %>
<%= f.text_field :category_title %>
</div>
<br>
<div class="field">
<%= f.fields_for :educations do |edu| %>
<div class="field">
<%= edu.label :sectionTitle %><br>
<%= edu.text_field :sectionTitle %>
</div>
<% end %>
</div>
<br>
<%= f.submit 'create' %>
<% end %>
Also here quite good source, Nested Form

How to pass id from javascript to rails forms

I want to pass the selected value from the drop down to fullcalendar plugin and the rails form
The select tag
<%= form_tag appointments_path, :html => {:id => "form-1"} do %>
<%= select_tag(:worker_id, options_from_collection_for_select(#client.workers, :id, :name), :selected => #a, :style=>"width:170px;", :prompt => "Select Staff Member")%>
<% end %>
I am passing the #a variable by ajax to
<script>
$('#worker_id').change(function (e) {
var a = parseInt($(this).val());
alert(a);
$.ajax({
type: "GET",
url:"/customers/new",
data : { id: a },
success:function(result){
$('#content1').html("<%= escape_javascript(render :partial =>'form', :locals => ????) %>");
}
});
$('#calendar').fullCalendar('destroy');
RenderCalendar($(this).val());
});
</script>
I am not sure whether i am doing it in right way. I want to pass the value in form which is here:
<%= form_for(#customer) do |f| %>
<%#= f.error_notification %>
<div class="field">
<%#= f.label :Service_Name %>
<%#= f.collection_select :service_id, Category.where(:client_id => #client).order(:name), :services, :name, :id, :service_name %>
</div>
<br /> <br />
<%= f.fields_for :appointments do |builder|%>
<fieldset>
<% if #a!=0 %>
<%= builder.hidden_field :worker_id, :value=> #customer.worker_id %>
<%= builder.hidden_field :client_id, :value=> #client.id%>
<%= builder.label :price %>
<%= builder.text_field :price %>
<%= builder.label :Service_Name %>
<%= builder.collection_select(:service_id, #a.order(:service_name), :id, :service_name, :include_blank => true, :multiple => true ) %>
<% end %>
<%= builder.label :appointment_date %>
<%= builder.date_select :appointment_date %> <br />
<%= builder.label :appointment_start_time %>
<%= builder.time_select :appointment_start_time, ampm: true %> <br />
<%= builder.label :appointment_end_time %>
<%= builder.time_select :appointment_end_time, ampm: true %>
</fieldset>
<%end%>
<div class="field">
<%= f.label :title %>
<%= f.text_field :title %>
</div>
<div class="field">
<%= f.hidden_field :worker_id, :value=>#customer.worker_id %>
</div>
<div class="form-actions">
<%= f.button :submit, :class=>"btn btn-primary" %>
</div>
<% end %>
If I understand correctly: you are trying to rerender the fullcalender jquery plugin with your ajax success callback based on the user selected from the select tag here:
<%= form_tag appointments_path, :html => {:id => "form-1"} do %>
<%= select_tag(:worker_id, options_from_collection_for_select(#client.workers, :id, :name), :selected => #a, :style=>"width:170px;", :prompt => "Select Staff Member") %>
<% end %>
There is an inherent issue with the way you're trying to do this. Any embedded ruby in your views will run only once at runtime. Essentially, your escape_javascript(render partial..... will not run because any embedded ruby is done running at that point.
What you could do is keep the ajax call you already have but run the render partial code in your '/customers/new', instead of trying to call it in the ajax callback -which is after runtime
render :partial =>'form', :locals => ????
This will return the partial code with which you want to then place on the page. With your ajax, simply place it on the page something like this:
success:function(result){
$('#content1').html(result);
}

how to include the javascript into dropdown list in ruby on rails?

I have a javascript file for the cascading dropdown boxes loading from different models. But I dont know how to include into the dropdown list.
Form:
<% content_for :javascript do %>
var master_surveys = <%=
Condition::MasterSurvey.all.map {|ms| {id: ms.Master_Survey_Code, to_s: ms[:Master_Survey_Name]}}.to_json.html_safe
%>
var elements = <%= elements = Hash.new { |hash, code| hash[code] = [] }
Condition::Element.all.each {|e| elements[e.Master_Survey_Code] << {id: e.Element_Code, to_s: e.Element} }.to_json.html_safe
%>
var sub_elements = <%= sub_elements = Hash.new { |hash, code| hash[code] = [] }
Condition::SubElement.all.each {|s| sub_elements[s.Element_Code] << {id: s.Sub_Element_Code, to_s: s.Sub_Element} }.to_json.html_safe
%>
var materials = <%=
materials = Hash.new { |hash, code| hash[code] = [] }
Condition::RenewSchedule.all.each {|rs| materials[rs.Sub_Element_Code] << {id: rs.Material_Code, to_s: rs.Material} }.to_json.html_safe
%>
$(document).ready(function(){
$('select#enr_rds_surv_rdsap_xref_master_survey').chainedTo('select#enr_rds_surv_rdsap_xref_Element_Code');
});
<% end %>
<%= form_for(#enr_rds_surv_rdsap_xref) do |f| %>
<% if #enr_rds_surv_rdsap_xref.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#enr_rds_surv_rdsap_xref.errors.count, "error") %>:</h2>
<ul>
<% #enr_rds_surv_rdsap_xref.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :Master_Survey %><br/>
<%= f.select :master_survey, Condition::MasterSurvey.all.map{|e| [e.Master_Survey_Code]}, { :prompt => 'Please Select' } %>
</div>
<div class="field">
<%= f.label :Element_Code %><br/>
<%= f.select :Element_Code, Condition::Element.all.map{|e| [e.Element, e.Element_Code]}, { :prompt => 'Please Select' } %>
</div>
<div class="field">
<%= f.label :Sub_Element_Code %><br/>
<%= f.select :Sub_Element_Code, Condition::SubElement.all.map{|e| [e.Sub_Element, e.Sub_Element_Code]}, { :prompt => 'Please Select' } %>
</div>
<div class="field">
<%= f.label :Material_Code %><br/>
<%= f.select :Material_Code, Condition::RenewSchedule.all.map{|e| [e.Material]}, { :prompt => 'Please Select' } %>
</div>
<div class="actions">
<%= f.submit 'Save'%>
</div>
<% end %>
So, The above javascript file collect the data from the parent. In the form, I created a dropdown list statically loaded the data from the database. I want to include the javascript to loaded automatically into the dropdown list dynamically.
Thanks in advance!!!!
I usually do it by Ajax and partials(or page, up to you.), not nice but might be help?
Bind change even on your parent selects. like
$("#parent_select").change(function(){
$.ajax({
url: '/parents/'+$(this).val()+'/childs/',
complete: function(data){
$('#children_select').html(data);
}
})
});
And in your child controller render a partial(or page) with only contents of options of selected children. like:
<%children.each do |child|%>
<option value='<%=child.id%>'><%=child.name%></option>
<%end%>

Categories