Jquery not firing events after first action call - ruby-on-rails

I implemented a feature where a user can update an objects attribute to true/false directly from the table output on click. Everything is working as it should for the first time, but after the ajax call is being done I cannot do it anymore. Maybe the DOM failed to load?
I have my table:
<div id="dashboard_pages_table" class="small-12 columns">
<%= render partial: 'layouts/admin/dashboard_pages_table', locals: {parents: #parents} %>
</div>
And the coffeescript which is listening to a click event on one td element:
jQuery ->
$('#sortable .onoff').on "click", (event) ->
page_id = event.target.parentElement.parentElement.id.match(/\d+$/)[0]
$.post 'update_row_onoff',
page_id: page_id
The coffeescript is calling the update_row_onoff method in my controller:
def update_row_onoff
#target_page = Page.find(params[:page_id])
if #target_page.active
#target_page.update_attribute(:active, false)
else
#target_page.update_attribute(:active, true)
end
respond_to do |format|
format.js
end
end
And then the update_row_onoff js.erb file is reloading the contents of the dashboard_table:
$('#dashboard_pages_table').html("<%= escape_javascript(render partial: 'layouts/admin/dashboard_pages_table', locals: {parents: #parents}) %>");
Why is it not working after the first successful post action?

Use this instead
$("body").on "click", "#sortable .onoff", (event) ->
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.
For details go to the api documentation, http://api.jquery.com/on/

Related

Rails: Populating modal with data

I know this is an old question, but I cant get it solved..
I want to show a list of comments in a modal, specific to each iteration.
Content has_many comments, Comment belongs_to content`
#contents.each do |content|
content.title
button_to('read', category_modal_path(:comment_id => content.id), remote: true, :class=> 'modal-trigger2', 'data-target'=>'modal3')
end
controller
def category_modal
#comments = Comment.online.where(content_id: params[:comment_id])
respond_to do |format|
format.js
end
the modal
<div id="modal3" class="modal modal-fixed-footer">
...here I want show the list of comments
category_modal.js
$('#modal3').html(<%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%> );
coffee
$('.modal-trigger2').leanModal()
Modal opens but no data.. help would be very nice..
Okay after an hour efforts I am able to solve your issue. Follow these steps.
First of all remove $('.modal-trigger2').leanModal() from coffee script. It does not need any more.
In category_modal.js paste the following code
$('#modal3').html("<div href='#modal3' id='content_<%=params[:comment_id] %>'><%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%></div>");
$('#content_<%=params[:comment_id]%>').leanModal();
$('#content_<%=params[:comment_id]%>').trigger('click');
You might need to add method: :get on your category listing If your route is not of post type so
#contents.each do |content|
content.title
button_to('read', category_modal_path(:comment_id =>content.id), remote: true, :class=> 'modal-trigger2',method: :get)
end
okay now tell me what was the issue.
Basically it was the mess of leanModal If you have used bootstap modal it would not be the problem.
Basically Whenever we call leanModal on any element It stops it default behaviour i-e Click So from now on when some one click on it , It open the popup in which it shows the corresponding content which was mentioned in href of the clicked item.
So when I call $('.SomeClass').leanModal() It will add a click event for all of the item having class SomeClass and open modal when some one click on it and show the content.
So in your case when you called $('.modal-trigger2').leanModal() It simply added a click event for all of your Contents buttons and open the popup whenever you clicked on any of it. It even didn't send an ajax call to server.
As you know initially there was not any content in modal3 container that's why it opened empty modal.
So now what I did was to remove this call and moved all of the popup logic in category_modal.js
So whenever you click on a Content it send an ajax request to server. In JS view I am doing the same thing you were doing but now I added a wrapper around your comments and set the ID unique depending on your requested content_id .
After that I call leanModal on this newly created wrapper div.
And trigger the click event on it so modal will show automatically.
P.S
You don't necessarily need this dynamic ID stuff following code will also work .
$('#modal3').html("<div href='#modal3' id='leanModalContainer'><%= j( render partial: 'shared/modal2', locals: {comments: #comments} )%></div>");
$('#leanModalContainer').leanModal();
$('#leanModalContainer').trigger('click');

How to display messages (aka flash) without rendering or redirecting

After form submit my controller checks if some conditions. In my case there are three of them:
if user rich maximum of his possibilities of objects tracking
if user already track this object
everything is ok, and request is added to queue
I'd like to inform user about those conditions. I have form with remote: true and now I show the info by render js: "alert('info')" but it looks ugly. I don't want to redirect user somewhere or rerender the form after form submit. I just want to display 'flash' message and wait to another request from user. How can I make it?
Simple approach:
On top of your form page, have a div to store the message:
In your request handler for the remote request in the controller, compute the message to show.
def create
...
#message = get_message
...
end
Since it is an ajax request, your view will be a .js.erb file (assuming you are using erb). In that view, just set the message div content as #message:
# create.js.erb
$('#message').text("#{#message}");
Advanced approach:
Alternatively, if you want richer formatting, create a partial for the message formatting and render it in the js.erb file.
For example, I use bootstrap for my styles, and I can make the message look like an alert with an 'x' to close it - so I create a partial to render the alert:
# views/home/_message.html.erb
<div class='alert alert-warning alert-dismissible'>
<%= message %><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
</div>
And in your js.erb you could do this instead,
# create.js.erb
$("#message").html("<%= escape_javascript(render partial: 'home/message', locals: { message: #message } ) %>");
If you want to use remote ajax requests, you'll need to handle the responce yourself on the frontend. If you want it to look pretty, you need to design a pop-up modal window or some kind of a show-up block on your page in wich to display a message. Make it style='display:none' for default.
Then you need to write a JS method to display it and return that method. Something like this. (assuming you're using jQuery)
$('#messageblockid .content').text("your message goes here");
$('#messageblockid').show();

Preventing a page from getting opened

When user clicks on a chart, I get some ID in the Javascript side of its onclick event and pass that as a query param to the page that I want to open and I say
window.open(go_to);
which goto will have that query param in it for exampel like "http://localhost:3000/myapp/people?provider=134"
so now it hits the index action method in the Rails side, in there I also get another variable for logged in user:
def index
cur_user_id = current_user.id
provider_id = params[:provider]
# call the REST service and pass those two params
# and get the appropriate JSON back from the service
if provider_id == cur_user_id
render nothing: true
end
end
The problem I have is with this logic:
if provider_id == cur_user_id
render nothing: true
end
So if logged in user is the same as the provider I don't want to open that page or show anything. Render Nothing is helping with not showing anything but still the window.open part of the code from Javascript is opening the page, blank tho
How can I tell it hey don't even open the new page?
You can use ruby code mixed with javascript:
var provider_id = $('#provider_id').val();
var go_to = '/path/to/somewhere?provider_id=' + provider_id;
if(provider_id == <%= current_user.id %>) {
alert('You cannot go there!');
} else {
window.open(go_to);
}
Remember that the ruby code will be executed first (on server-side), then your HTML/javascript will be generated, and finally be executed on the client-side. So <%= current_user.id %> inside the javascript will just print the value in there, like if it was hard-coded in JS.
It seems that you didn't know about the ruby code inside the javascript parts, to give you an example, try this in one of your view using Javascript:
# this is on the server-side, it will be generated:
<script type="text/javascript">
<%= "alert('hello Eric!');".html_safe %>
</script>
# on the client-side, you will receive this generated HTML content:
<script type="text/javascript">
alert('hello Eric!');
</script>
For HAML:
:javascript
#{"alert('hello Eric')".html_safe}
var hello = '#{"hello World!"}';
alert(hello);

Rails jQuery Tokeninput Reload via AJAX

I have an AJAX create action for a rails controller that will select the form and recreate it by doing a render partial of just the form. This way, the error messages get shown when the validation fails.
However, one of my text fields is using the jQuery TokenInput plugin, and when the ajax call redraws the form, the jQuery TokenInput plugin is no longer loaded on the form.
Is there any way to trigger rerunning of the corresponding assets/javascripts/.js.coffee file from the AJAX controller action javascript file?
Thanks in advance...
After the form is redrawn, you just need to rerun your Tokeninput script. The best way to do this would be to place your Tokeninput command into a function (so you don't repeat yourself) and then just call that function after the form render. For example, let's say you want a Dog model that has_many collars that you want tokenized:
dogs.js.coffee:
tokenizeDogCollars = ->
$("#dog_collar_tokens").tokenInput "/dogs.json"
tokenizeDogCollars
create.js.erb:
<% if #dog.errors.any? -%>
...
$('#dog-form-container').empty();
$('#dog-form-container').append('<%= j render("form") %>');
tokenizeDogCollars();
...
<% else %>
... whatever you want to do on a successful save ...
<% end %>

Rendering a completely new partial using jquery ajax

I'm trying to write an AJAX call that renders a new partial when a particular item is selected from a drop down list. I have been searching for a solution all day with no luck :(
The only way I got it working was not using AJAX, but having a hidden div containing my second partial, and then showing it and hiding the other div when the appropriate option is selected from the drop down box. Yes this worked but I was looking for a cleaner solution.
I'm not looking for a direct answer, but if anyone has any resources that could point me in the right direction it would be greatly appreciated :)
How about adding a controller action that would render the view (so it's view would just render the partial), and then using jquery to place it:
$('#id-of-box').load("<%= some_action_path %>")
You should perform a remote AJAX call when the onchange event from your select element is being triggered, so on the page which contains your select element there should be something like this (inside a script):
$('#select_id').live('change',function(){
$.ajax({
url: 'url_bound_to_partial_renderer'
});
}
and on the action of the controller which responds to your url_to_fetch_result, you should write something like this:
# controller
# action bound to 'url_bound_to_partial_renderer' by routes.rb
def partial_renderer
...
end
#view (partial) _partial_renderer.js.erb
$('jquery_selector_path_to_container_element_of_your_partial').html("<%= escape_javascript render(:partial => 'my_partial') %>");
#view (partial) to be rendered inside container element: _my_partial.html.erb
<p>Here goes the content of the partial you want to be rendered on the container!</p>
Hope this will respond to your question.

Resources