ajax won't fire on subsequent modal forms - javascript

I've got this index of items listed out on a page, and on this page each item has a link that pops open a unique modal. in this modal i have a :username text field and a corresponding ajax call so when you type #username the usernames of your friends pop up (novel idea, right?). Anyway, it only works for the first item-link-modal combo, then the subsequent item/link/modal combos don't function. here's where i'm stuck, any help greatly appreciated:
modal partial:
<div class="modal fade" id="pirateinvite-<%= x.id %>" tabindex="-1"
role="dialog" aria-labelledby="pirateinviteLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="pirateinviteLabel">Invite a friend</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
blah blah
<%= form_for #invitations, :url => invitations_path, :method => 'create', remote: true do |b| %>
<div class="form-group"><center>
<b><%= b.label :username, 'Invite by username:' %></b></center>
<%= b.text_area :username, rows: 1, class: 'form-control', required: true, placeholder: "#user1 #user2" %>
<%= b.hidden_field :event_id, :value => x.id %>
</div>
<div class="text-center">
<%= b.submit 'Send an Invite!', class: 'btn btn-primary btn-sm align-self-center' %>
<% end %></div>
</div>
</div>
invitations.coffee
class #Invitation
#add_atwho = ->
$('#invitation_username').atwho
at: '#'
displayTpl:"<li class='mention-item' data-value='(${image},${name})'><img src=${image}>#${name}</li>",
callbacks: remoteFilter: (query, callback) ->
if (query.length < 1)
return false
else
$.getJSON '/mentionsy', { q: query }, (data) ->
callback data
jQuery ->
Invitation.add_atwho()

Needed to make each textarea id in the modals unique by changing it to <%= b.text_area :username, id: "invitation_username_#{+ x.id}", rows: 1, role: "textarea", class: 'form-control', required: true, placeholder: "#user1 #user2" %>
Needed to change atwho listener to listen for all of those unique text areas like so: $('textarea[id^=invitation_username_]').atwho

Related

How do I autofocus to text input field in modal? Rails 7, Bootstrap 5

I have a search button in the top navbar. When the user clicks, a modal opens with a text input field. I want the keyboard focus to be automatically inside the text input field when the modal opens.
Here is the search modal code:
<div class="modal" id="searchModal" tabindex="1" aria-labelledby="searchModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="searchModalLabel">Search parks</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<%= search_form_for #q, url: :parks do |f| %>
<%= f.hidden_field :has_entrance_fee_eq %>
<%= f.hidden_field :region_eq %>
<div class="form-group">
<%= f.text_field :name_en_or_name_he_or_description_en_or_description_he_cont,
autofocus: true,
placeholder: "Search for a park (English or Hebrew)",
class: "form-control" %>
</div>
<div class="form-group">
<%= f.submit 'Search parks', name: "", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
I've already tried simply adding autofocus: true in the rails form, but it doesn't work:
<div class="form-group">
<%= f.text_field :name_en_or_name_he_or_description_en_or_description_he_cont,
autofocus: true,
placeholder: "Search for a park (English or Hebrew)",
class: "form-control" %>
</div>
The Bootstrap documentation says:
Due to how HTML5 defines its semantics, the autofocus HTML attribute has no effect in Bootstrap modals. To achieve the same effect, use some custom JavaScript:
var myModal = document.getElementById('myModal')
var myInput = document.getElementById('myInput')
myModal.addEventListener('shown.bs.modal', function () {
myInput.focus()
})
But I'm not really familiar with Javascript so not sure where/how to use this code, if this is indeed the right direction... In general I'm new to coding so any help would be much appreciated, the more specific the better!
Update:
I tried adding the following code to the search modal but it didn't work:
<script>
// Get the modal and the input element
var myModal = document.getElementById('searchModal')
var myInput = document.querySelector('input')
// Add a listener for the shown.bs.modal event on the modal
myModal.addEventListener('shown.bs.modal', function() {
// When the modal is shown, focus the input element
myInput.focus()
})
</script>

Manually adding select options does not work correctly every time, and even if it did, the second atempt is always a failure

I want to create a modal with three text_fields, and when submitting, I need to preventDefault on the browser (to not reload the page, in case any data was put beside modal), then send data to the backend through AJAX, and then manually update the select_2 with submitted option.
Changing variables types, splitting .trigger("change") into a new line, or zeroing option object after appending it, doesn't seem to change anything.
<div class="sampling-register">
<div class="ibox">
<div class="ibox-content">
<form>
<div class="section">
<div>
<%= select_tag :client, grouped_options_for_select(#clients),
:include_blank => 'Wybierz klienta', class: 'select2_demo_2', required: true %>
<button type="button" data-toggle="modal" data-target="#client_modal">
<%= image_tag 'laboratory/add_circle_blue' %>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="modal inmodal" id="client_modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content animated fadeIn">
<div class="modal-header">Dodaj klienta</div>
<%= form_for :client, url: clients_path, :html => {:id => "form_add_client"} do |f| %>
<div class="modal-body">
<%= f.hidden_field :laboratory_id, value: current_user.company.laboratory.id %>
<%= f.text_field :name, class: 'form-control', placeholder: 'Nazwa', required: true %>
<%= f.text_field :address, class: 'form-control', placeholder: 'Adres' %>
</div>
<div class="modal-footer">
<button class="discard" data-dismiss="modal">Anuluj</button>
<button class="submit">Dodaj</button>
</div>
<% end %>
</div>
</div>
</div>
<script>
let form = $("#form_add_client");
let submitBtn = form.find(".submit");
let client_select_tag = $("#client");
form.on("submit", function (event) {
event.preventDefault();
let name = $('#client_name').val();
let client_address = $('#client_address').val();
let laboratory_id = $('#client_laboratory_id').val();
$.ajax({
url: '/clients',
method: 'POST',
dataType: "json",
data: {
client: {
name: name,
address: client_address,
laboratory_id: laboratory_id
},
}
})
.done(function (result) {
if (result.error) {
toastr["error"](result.error);
} else {
let option = new Option(result.data.name, "{lab_client_id: " + result.data.id + "}", false, true);
client_select_tag.children().eq(2).append(option).trigger('change');
$('#client_modal').modal('hide');
toastr["success"]("Klient dodany poprawnie");
}
})
})
</script>
The problem is, it does works, but then sometimes doesn't (like every third try), and even if it works once, then every other attempt is a failure until I reload the page. After reloading, it seems like a coin throw again.
It does trigger the appended option as selected EVERY time, but actually appending to the select list does not occur so often.
OK, seems that changing
client_select_tag.children().eq(2).append(option).trigger('change');
into
client_select_tag.select2().children().eq(2).append(option).trigger('change');
makes the code works

uncaught TypeError: ajaxForm is not a function in rails version 5?

I am trying to submit the modal form using ajaxForm and display the response in modal itself. But, I am getting uncaught type error (...).ajaxForm is not a function.
Basically I want to create a modal form for lesson creation form and have to submit , my app consists of both API controller and front end controller.
api!
param_group :lesson
description 'creates a lesson'
example "
{
'id': 12,
'title': 'MUDRAS',
'active_video_id': 3,
'description': 'Description of the lesson',
'points': null,
'is_public': '1',
'videos': [
{
'video': {
'id': 1,
'video': {
'url': '/uploads/video/video/1/250-authentication-from-scratch.mp4'
},
'title': null,
'storage_type': 'Lesson',
'storage_id': 12
}
},
]
}"
def create
#lesson = Lesson.new(lesson_params)
#lesson.creator = current_user
if #lesson.save
render json: {
success: true,
message: "Lesson created Successfully"
}
else
render json: { success: false, message: "Could not Create : #{#lesson.errors.full_messages.join(', ')}" }
end
end
def new
#lesson = Lesson.new
end
The above code is my API controller.The below codes are my Front end controller and lesson related forms.
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
render json: {
success: true,
message: "Lesson Created Successfully"
}
else
render json: {
success: false,
message: "Lesson Creation Failed"
}
end
end
I need to display the "New Lesson" button in Lesson Index page.
lessons/index.html.erb
<% unless current_user.student? %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<div id="newLesson" class="lesson-category btn-danger" lesson_url="<%= new_lesson_path %>">
<i class="fa fa-plus"></i> ADD LESSON
</div>
</div>
</div>
<div class="hidden" id="newLessonForm">
<% #lesson = Lesson.new ; #lesson.videos = [Video.new] %>
<%= render "lessons/form" %>
</div>
<% end %>
<%= render "shared/primary_modal" %>
<div class="container-fluid">
<div class="col-md-3 col-sm-3 text-left">
<h2 class="main-tab tab-active">LESSONS</h2>
</div>
<div class="col-md-9">
<div class="col-md-12 text-right">
<h2 class="main-tab tab-inactive"><a id="responsesLink" class="blacko" href="#"><%= "MY" if current_user.student? %> RESPONSES</a></h2>
</div>
</div>
<div class="col-md-12"><hr/></div>
<!-- Lessons of this course Go here -->
<div class="col-md-3">
<% #lessons.each do |lesson| %>
<div id="lesson_<%= lesson.id %>" class="pill video-view lesson-load" data-lesson-id="<%= lesson.id %>" data-src="<%= lesson.active_video_url %>"><%= lesson.title %></div>
<% end %>
<!-- <div class="pill pill-inactive">Something</div> -->
</div>
<!-- Lesson Content goes here -->
<div class="col-md-9">
<div class="row">
<div class="col-md-12">
<%= render "shared/video_player" %>
</div>
</div>
<div id="lessonContent">
</div>
</div>
</div>
<script>
$("#newLesson").click(function(){
var lesson_path = $(this).attr("lesson_url");
$.get(
lesson_path,
function(content){
$("#primaryModalContent").html(content);
$("#format").val('js');
$("#primaryModal").modal("show");
}
);
});
</script>
My lesson creation form is given as a partial.
<div class="col-md-12">
<%= simple_form_for #lesson, html: {class: "newLessonform"} do |f| %>
<%= f.input :title, label: "Lesson Title", required: false %>
<%= f.input :description, required: false, as: :text %>
<%= f.input :points, required: false, as: :integer %>
<%= f.input :is_public, label: 'Check to Make this lesson public', as: :boolean %>
<div class="col-md-12">
<% unless #lesson.new_record? or #lesson.active_video_url.blank? %>
<h4> Currently Linked Video </h4>
<video src="<%= #lesson.active_video_url %>" style="width: 400px;"></video>
<% end %>
<hr/>
</div>
<h4>Add <%= #lesson.videos.blank? ? "a" : "another" %> Video</h4>
<% #lesson.videos = [Video.new(title: "")] if #lesson.videos.blank? %>
<%= f.simple_fields_for :videos do |g| %>
<%= g.input :title, label: "Video title" %>
<%= g.input :video, as: :file, lebel: "Select Video" %>
<% end %>
<center><%= f.submit class: "lesson-category btn-danger" %></center>
<% end %>
</div>
<script type="text/javascript">
$(".newLessonform").ajaxForm(function(data) {
$("#primaryModalContent").html(data.message);
});
</script>
In the above script , I have given ajaxForm. The modal form for this is given below.
<div class="modal fade" id="primaryModal" role="dialog">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" , data-dismiss="modal">×</button>
<h1 class="modal-title" id="modalTitle"></h1>
</div>
<div class="row modal-body" id="primaryModalContent">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
The error in chrome console , was uncaught error:(...)$.ajaxForm is not a function.
I am stuck in this for about a week. Could any one give me a solution.
Thanks in advance.
The best way to use an AJAX form in rails is to use rails_ujs.
First you have to tell rails_ujs that you want an AJAX action on your form :
<%= simple_form_for #lesson, html: {class: "newLessonform"}, remote: true do |f| %>
Then add a new file in your views, this view will be rendered after a successfull create action initiated by an AJAX action : views/lessons/create.js.erb
Inside you can put you js code, this code will be executed on the same page as the AJAX form. This is just a view and you can use variables from the controller.
$("#primaryModalContent").html("<%= #message %>")
Finally, you need to update your controller to handle AJAX action :
def create
#lesson = Lesson.new(lesson_params)
if #lesson.save
#success = true
#message = "Lesson Created Successfully"
else
#success = false,
#message = "Lesson Creation Failed"
end
respond_to do |format|
format.js
end
end
Here you can find some documentation about Rails UJS :
http://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements
https://blog.codeship.com/unobtrusive-javascript-via-ajax-rails/

Rails + AJAX: Load modal with ActiveRecord Object

I have a Product model I would like my user to be able to click a link in the view which will cause a modal to show with data specific to a given product. I have the product id stored in the links data-attribute.
# Modal
<div class="modal" id="product-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title text-center"><strong>Nutrition Facts:</strong></h4>
</div>
<div class="modal-body"></div>
</div>
</div>
</div>
Then I have the links that users will click:
# They click the label containing the data-attribute
<% #products.each do |prod| %>
<%= f.label prod.name, data: {id: prod.id}, class: "product-info" %>
<% end %>
This calls an ajax function:
$(".product-info").click(function() {
url = "/products/" + $(this).data("id")
$.get(url, function(data) {
console.log(data) # nothing shows here
}, 'script')
})
...finally I have my products/show.js view with the following:
$(".modal-body").html(<%= escape_javascript(render :partial => '/food_orders/nutrition', :locals => {prod: #product}) %>)
$("#product-modal").fadeIn();
console.log("Is this working?"); # I never see this in the console
and in my developer tools, the response to the ajax request contains show.js but it's never displayed to the user.
The whole issue was due to the fact that my erb was not in quotes.
I changed:
$(".modal-body").html(<%= escape_javascript(render :partial => '/food_orders/nutrition', :locals => {prod: #product}) %>)
to:
$(".modal-body").html("<%= escape_javascript(render :partial => '/food_orders/nutrition', :locals => {prod: #product}) %>")

How can I render the show action inside of the Bootstrap 4 Modal?

I'm having with populating the bootstrap 4 modal with a show action for a clickable image link. I'm currently using Carrierwave for uploading images. At this point, when I click the image, only the modal overlay displays. The modal container with content inside of it, doesn't show at all.
User/Show.html.erb
<div class= "container">
<div class="username">#user.username</div>
<div class="posts_container_pos">
<hr style="border: 2px solid #515558;">
<%= render 'posts/posts', post_items: #user.posts %>
</div>
</div>
Posts/_Posts.html.erb
<div class"container-fluid">
<%= #post_items.each do |post| %>
<%= link_to image_tag(post.photo.url(:medium), style: 'height: 300px; width: 500px;'), modal_post_path(post), data: {:toggle => 'modal', :target => '#reusable_modal'}, lazy: true %>
<div id="post-modal" class="modal fade"></div>
<!-- Modal -->
<div class="modal fade" id="reusable_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
<% end %>
<script type= "text/javascript">
$(document).on('page:change', function () {
$(document).on('click', '#reusable_modal [data-dismiss="modal"]',
function (e) {
$(e.target).removeData('bs.modal');
$('#reusable_modal').find('.modal-content').empty();
});
$(document).on('click', '[data-target="#reusable_modal"]', function (e) {
$("#reusable_modal").find(".modal-content").load($(this).attr("href"));
});
});
</script>
</div>
Posts/Modal.html.erb
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<i><%= image_tag(#post.user.avatar_url(:thumb), class: 'round-image-50') %></i>
<h4 class="modal-title" id="myModalLabel" style="margin-left: 60px; margin-top: -42px;"><%= post.user.username %></h4>
</div>
<div class="modal-body">
<% if #post.photo.present? %>
<%= image_tag(#post.photo.url(:large), style: 'max-width: 570px;') %>
<% end %>
<div class="modal_post_pos">
<%= sanitize content_with_emoji(#post.body) %>
</div>
</div>
<div class="modal-footer">
<%= render partial: 'comments/template', locals: {commentable: #post, new_comment: #comment} %>
</div>
Users_Controller.rb
def show
if params[:id].to_s.match(/^[0..9]+$/) && !User.friendly.exists?(params[:id])
render 'public/404.html', status: 404
else
#user = User.friendly.find(params[:id])
#post_items = #user.posts.paginate(page: params[:page])
end
end
Posts_Controller.rb
def modal
render layout: false
end
def show
#post = Post.find(params[:id])
#new_comment = Comment.build_from(#post, current_user.id, "")
respond_to do |format|
format.html
format.js
format.json {render json: #post }
end
end
Routes.rb
resources :posts, except: [:edit, :update] do
member do
get 'like', to: 'posts#like'
get 'dislike', to: 'posts#unlike'
get :modal
end
end
Server Log
Started GET "/posts/13/modal" for 127.0.0.1 at 2016-04-11 11:41:00 -0400
ActiveRecord::SchemaMigration Load (0.5ms) SELECT "schema_migrations".* FROM "schema_migrations"
Processing by PostsController#modal as HTML
Parameters: {"id"=>"13"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1 [["id", 5]]
Rendered posts/modal.html.erb (47.5ms)
Completed 500 Internal Server Error in 240ms (ActiveRecord: 1.5ms)
NoMethodError - undefined method `user' for nil:NilClass:
app/views/posts/modal.html.erb:5:in `_app_views_posts_modal_html_erb__227267806_63456696'
Since you dont have any instance variable #post defined on _posts partial and still trying to call it within _posts, its throwing up error.
The approach to solve this issue if you want to use Bootstrap Modal without extra js script is to bring _post partial code to _posts partial itself and <% end %> the loop after modal.
<% #post_items.each do |post| %>
<%= link_to image_tag........................
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Post Show</h4>
</div>
<div class="modal-body">
# complete partial code goes here
</div>
</div>
</div>
</div>
<% end %>
Obviously above approach is not good for performance as it will render everything without the need for it.
Better approach is to use Ajax using jQuery (my preference). listen for this button event (onClick) and load modal on the fly using ajax get method. consider looking at this approach for better performance reasons.
The second solution i am talking about is well explained here: https://stackoverflow.com/a/22144587/2545197
Maybe something like this?
In your JS
var $modal = $('#ajax-modal');
$.fn.modalmanager.defaults.backdropLimit = 1;
$('.modal-link').on('click', function(){
var modal_url = $(this).data("modal-url");
if(modal_url != null){
// create the backdrop and wait for next modal to be triggered
$('body').modalmanager('loading');
$modal.empty().load(modal_url, '', function(){
$modal.modal();
// Any callback functions such as let's say selectpicker
// $('#ajax-modal .selectpicker').selectpicker('refresh');
});
return false;
}
});
and in ERB
<%= link_to 'Show', post_path(#post), class: 'modal-link', data: { modal_url: post_path(#post) } %>
I solved this problem by simply rendering the file for the modal show view instead of the normal show action.
def show
#post = Post.find(params[:id])
#new_comment = Comment.build_from(#post, current_user.id, "")
respond_to do |format|
format.html {render :file => "posts/modal", layout: false}
format.js {render :file => "posts/modal", layout: false}
format.json {render json: #post }
end
end

Categories

Resources