Fire javascript ajax partial after each load using rails - ruby-on-rails

I have a menu item that fires ajax that returns javascript partial that is a bootstrap modal. The problem I am having is when a user clicks the menu item the first time, the modal opens as expected. The user closes the modal and tries to open it again, it doesn't open (although the ajax fires again from backend).
Consider the following code (using bootstrap 4):
Menu.html.erb:
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
<%= link_to user_profile_path(current_user.user_profile.id), remote: true, class: "dropdown-item" do %>
<%= fa_icon "id-card", text: "Profile Settings" %>
<% end %>
</div>
...
<div id="user_profile"></div>
user_profile/show.js.erb (ajax js partial):
$("#user_profile").replaceWith("<%= j render "user_profile" %>");
user_profile/_user_profile.html.erb (bootstrap modal):
<script>
$('#user_profile_modal').modal('show');
</script>
<%= form_with model: #user_profile do |f| %>
<div class="modal fade" id="user_profile_modal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
...
</div>
</div>
<% end %>
Is there a way to fire the the modal('show'); each time the modal is fired from the backend? By the way, this is just one of 3 modals that get loaded this way on the page.
Thanks again!

After trying a few things, simply replacing the replaceWith with html in the user_profile/show.js.erb will cause the ajax to fire each time.
Old:
$("#user_profile").replaceWith("<%= j render "user_profile" %>");
New:
$("#user_profile").html("<%= j render "user_profile" %>");
The reason for this is because the replaceWith is replacing the element in the parent, and thus not firing again because the element has already been replaced the first time.
Hope that helps anyone in the future!

Related

Ruby on Rails app glitching when Chrome auto complete is being used

I have a weird bug that hangs up or makes my app unusable or freezes for a minute.
So I have a 2 forms side by side one for billing and one for shipping and it has a drop down that uses the select2 library. When a user selects this drop down the Chrome autocomplete shows up too. It's overlapping the select2 dropdown. Here's an image:
So the problem here is when the user uses that drop down to select a country and uses the Chrome autofill instead of the select2 drop down and hits the enter key the form on the right fills the country and hangs up or freezes the app. Also when they choose a country or a state it will do a get request to the server.
What I tried are:
turn off the Chrome autocomplete on the settings; it works with no issues. The form on the right won't be updated (so I concluded it was Chrome)
I added an html: {autocomplete: 'off'} but this doesn't work, and I don't know why.
Here's the form:
<%= form_for [:admin, #corporate_account], html: { autocomplete: "off" } do |f| %>
<fieldset data-hook="new_property">
<div class="row">
<div class="col-md-12">
<%= render partial: 'form', locals: { f: f } %>
</div>
</div>
</div>
<div class="col-md-12">
<%= render partial: 'address_form', locals: { f: f } %>
</div>
</div>
<div class="form-actions">
<%= render partial: 'spree/admin/shared/new_resource_links' %>
</div>
</fieldset>
<% end %>
Update
I found that when I hit the enter with the Chrome autocomplete it sends a GET request, but with the regular drop down from the app it doesn't. I think Chrome's autocomplete after hitting the enter key it sends the form.
We are using select2 for our searches. It uses jQuery and ids are dynamically added. I found the script attaches the ID dynamically. It wasn't in the .js file, it was inside the .erb file. I've added this .js script inside the .erb file.
<% content_for :head do %>
<%= javascript_tag do %>
$(document).ready(function(){
$('span#<%= s_or_b %>country .select2').on('change', function() { update_state('<%= s_or_b %>'); });
<%# bellow this comment the code that I added %>
<%# this IDs are gnerated dynamically by select2 %>
const countryID = $('span#<%= s_or_b %>country .select2 .select2-search input').attr('id')
const stateID = $('span#<%= s_or_b %>state .select2 .select2-search input').attr('id')
<%# add the type attribute search so autocomplete can be toggled on and off %>
$(`#${countryID},#${stateID}`).attr('type', 'search')
<%# on focus set the autocomplete attribute off %>
$(`#${countryID},#${stateID}`).on('focus', function(){
$(`#${countryID},#${stateID}`).attr('autocomplete', 'off')
})
});
<% end %>
<% end %>
So when I focus on the search input, Chrome's autocomplete is not working any more.

I want my carousel to be appeared in index page only in rails application

I am new to rails and I want my carousel code to be seen in the index page only,please give a solution and below is my code :
<body>
<%= render 'layouts/navigation'%>
<%= render 'layouts/carousel' %>
<%= render 'layouts/messages'%>
<div class="container">
<div class="row">
<%= yield %>
<div class="col-md-8">
</div>
<div class="col-md-4">
</div>
</body>
Normally you'd want the move any code that's specific to a page out of the layout and into the template for the appropriate action.
However, in your case that piece of code looks embedded within the rest of the page skeleton so it could be hard to refactor it that way.
For this reason I'd suggest using conditional rendering by simply using a Boolean variable.
For example you could do:
<%= render 'layouts/carousel' if #render_carousel %>
And then you could just set the #render_carousel variable to true for any action that you'd want the carousel to appear in, e.g.:
def index
# rest of the code
#render_carousel = true
end

ROR pass params to modal

I'm trying to open a modal that displays a list of items. The list of items is already available in the view as a variable. How do I pass this variable to the modal?
Below is roughly how the main view looks like:
View.html.erb
<div>
<%= #users.each do |user|%>
<h1>user.name</h1>
<h2>user.email</h2>
<%= link_to remote: true, 'data-toggle' => 'modal', 'data-target' => '#taskModal do %>
<i><%= user.tasks.count%></i>
<% end %>
<% end %>
</div>
<div class="modal" id="taskModal" aria-hidden="true">
...
<%= render partial: 'list_modal' %>
list_modal is a partial with the structure of the modal.
As opposed to having the list of items already on the view, and wanting to pass it to the modal, One thing you can do is make the button ( or link ) for opening the modal to call a controller action by ajax, and then let the action respond to JS, where you will now use the corresponding view.js file to both populate the modal as well as programmatically render it ( after populating it ).
Example:
Link to open modal:
<%= link_to "Open users list", users_open_list_modal_path, remote: true %>
Users open list modal controller action:
def open_list_modal
#user_list = User.all
respond_to do |format|
format.js
end
end
open_list_modal.js.erb:
//populate modal
$('#modal').html('#{ escape_javascript(<%= render partial: 'user_list', locals: {user_list: #user_list} %> )}');
//render modal
$('#modal').openModal();
And then on the modal itself, you can now have access to the user_list (NOT #user_list) list.
Note: In this example, I made use of both erb, js, and material-modal. If you are using something different from these ( maybe slim, haml, coffee, bootstrap...), you will have to suite the example to your case.
Hope this helps.
you can just directly pass it to modal. here what i did thou, on my view i have a button that trigger my modal and then i created a partial (to DRY up my code) _modal.html.erband called that partial after my button.
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#modal"></button
<%= render 'modal' %>
make sure your modal has id <div class="modal fade" id="modal" tabindex="-1" role="dialog">...
gl mate!
You can set it as how you would normally do for view components. Better yet, separate out your model into partial, say it's _modal.html.erb. Then you can call the modal by
<%= render 'partial_name', :variable_name => your_current_variable %>
The variable would now be available as variable_name inside the partial. Also, if it's an instance variable like #your_current_variable then it will be automatically available in your partial.

Displaying form error notifications within modal

I'm new to Rails and have been struggling with this issue for many hours - would really appreciate any help.
I have a signup form (using Devise and simple_form) inside a Bootstrap modal and would like error notifications to be displayed within the same modal when the form is submitted. Currently, when the form is submitted with errors, the page redirects to /users and the errors are rendered there. When the form is submitted without errors, the page stays on the home page and displays a 'success' flash message as desired.
I don't know whether this issue is caused by a controller/routing problem, whether I need to (first learn then) add in jQuery/Javascript/Ajax, or something else.
Modal code (contained in a partial)
<div id="signupModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="signupLabel" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="signupLabel">Sign up</h3>
</div>
<div class="modal-body">
<%= simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: {class: "form-horizontal"}) do |f| %>
<%= f.error_notification %>
<%= f.input :name,
placeholder: 'John Smith',
input_html: {class: 'span7'} %>
...
<div class="form-actions">
<%= f.submit "Sign up", class: "btn btn-large btn-success" %>
</div>
<% end %>
</div>
</div>
application_helper.rb - this code was added after reading this SO question
module ApplicationHelper
def resource_name
:user
end
def resource
#resource ||= User.new
end
def devise_mapping
#devise_mapping ||= Devise.mappings[:user]
end
end
You should add a :remote => true to your form, this causes the form to be submitted via Ajax. You then need to modify your controller to respond_to format.js. It should attempt to save the record. If there are errors, it should reply with create.js.erb which has something like the following in it:
$("#errors_div").html("<%= #resource.errors.full_messages %>")
If you look under the hood of simple_form you'll see that it adds some new css 'error' classes and spans with the error messages in them, based on evaluating the results of the #model.errors array.
I don't believe that the form is designed to handle error message display when the submit is done via ajax. I think your options are:
Render the resulting form to a string on the sever side via 'render_to_string' and then replace the contents on the page using a jQuery callback handler or via rendering the response as a js template.
Return the results as json, including the #model.errors and then in javascript use this info to update the form with error messages.
I'd start with option #1, as it is a little simpler.

Render page rails, modal

I am currently trying to optimize rendering a page in ruby on rails.
I have a question, is there a way to make a page, only render another page when a link (href) associated to it is clicked.
some codes in index.html.erb:
.....
.....
<h4>
<%= item.name %>
<br/>Details
</h4>
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>
.....
.....
In code above, I am using modal. So that when the link is clicked, _item.html.erb will be shown appear in a smaller page. Similar like a popup.
When index.html.erb is loaded, then all codes inside _item.html.erb will also be loaded automatically and all queries inside will be executed because of
<%render item%>
code.
What I want is, I don't want index.html.erb also render all item inside _item.html.erb page unless I click "Details" button.
<br/>Details
I think by doing this think, I can save some amount of time when a user requests for item page, because the system doesn't need to retrieve all information which are not yet required.
Could you guys help me?
Please let me know if you need another information.
You have to use ajax in order to achieve this. You can create a hidden div with a specific id, say "modal".
Revert your h4 to this:
<h4>
<%= item.name %>
<br/>
= link_to 'Details', item_path(item), data: {remote: true}, item_details: true
</h4>
Then in your item controller, on the show action:
def show
# load the item
if params[:item_details]
respond_to {|format| format.js}
else
# do what you already do here
end
end
And in your item views folder, create a file show.js(.coffee):
$('#modal').html('<%= j(render partial: "item", object: #item) %>');
$('#modal').modal('show');
This is just the idea, you have to make it compatible with your code.
If you want to go the ajax route:
<h4>
<%= item.name %>
<br/>
<%= link_to "Details", item_path(item), remote: true %>
</h4>
Then in your items_controller:
def show
...
respond_to do |format|
format.js
end
end
Then create the view "views/items/show.js"
$(body).append(<%= escape_javascript(render partial: "items/item_modal") %>);
...code to show modal...
...hook to remove modal when it is dismissed...
And the view "views/items/_item_modal.html.erb"
<div id="<%=item.id%>_item_modal" class="modal fullscreen">
<div class="item-modal">
<%=render item%>
</div>
</div>

Resources