Ajax won't be reloaded properly every 3 seconds. Why? - ruby-on-rails

I'm trying to make it reload the partial that shows the number of messages unread every 3seconds.
But the codes I wrote won't show the numbers at all even if there's 1 unread message...
How can I reload partial that shows correct number of messages unread??
My codes are
assets/javascript/refresh_messages_count.js
$(document).ready(function () {
// will call refreshPartial every 3 seconds
setInterval(refreshPartial, 3000)
});
function refreshParital() {
$.ajax({
url: "messages/refresh_part";
})
}
messages_controller.rb
def refresh_part
#message_count = current_user.mailbox.inbox(:read => false).count(:id, :distinct => true)
# get whatever data you need to a variable named #data
respond_to do |format|
format.js {render :action=>"refresh_part.js"}
end
end
views/layouts/_menu.html.erb
<span id="message_received_count">
<%= render :partial => "layouts/message_received_count" %>
</span>
views/layouts/_message_received_count.html.erb
<% if user_signed_in? && current_user.mailbox.inbox(:read => false).count(:id, :distinct => true) > 0 %>
<li><%= link_to sanitize('<i class="icon-envelope"></i> ') + "Received" + sanitize(' <span class="badge badge-info">'+#message_count.to_s+'</span>'), messages_received_path %>
</li>
<% else %>
<li><%= link_to sanitize('<i class="icon-envelope"></i> ') + "Received", messages_received_path %>
</li>
views/messages/refresh_part.js.erb
$('#message_received_count').html("#{escape_javascript(render 'layouts/messages_received_count', data: #message_count)}");

Change your function refreshPartial to the following:
function refreshPartial() {
$.ajax({
url: "/messages/refresh_part",
type: "GET",
dataType: "script",
success: function(data) {
console.log("Called refresh_part");
},
error: function (xhr, ajaxOptions, thrownError) {
alert("Error: " + xhr.status + " " + thrownError);
}
});
}
(the / in front of messages is important, the other fields are useful as well - you can remove the success option once you get it working).
And change your method in your controller to:
def refresh_part
#message_count = current_user.mailbox.inbox(:read => false).count(:id, :distinct => true)
# get whatever data you need to a variable named #data
respond_to do |format|
format.js
end
end
(removing the render part - rails knows how to do this automatically).
Edit
After discussion - the last problem to be resolved was related to JQuery conflict - JQuery was being included in multiple places and stopping the $(document).ready from firing. Fixed.

Related

Rails how to update the page with the help of Ajax

The object Task contains a boolean field done. How to Ajax refresh the page after the change of status? And instead true - false display value complete - incomplete?
routes.rb:
resources :tasks do
member do
post 'done'
end
end
Controller:
def done
#task = Task.find(params[:id])
#task.update_attributes(:done => params[:done])
respond_to do |format|
format.js {}
end
end
View:
....
<td><%= task.done %></td>
<td><%= check_box_tag 'done', task.id , task.done, :class => "task-check", remote: true %></td>
....
<script>
$(".task-check").bind('change', function(){
$.ajax({
url: '/tasks/'+this.value+'/done',
type: 'POST',
data: {"done": this.checked},
});
});
</script>
Update
edited script
<script>
$(".task-check").bind('change', function(){
$.ajax({
url: '/tasks/'+this.value+'/done',
type: 'POST',
data: {"done": this.checked},
}).done(function(ajax_response){
location.reload();
});
});
</script>
and controller
def done
#task = Task.find(params[:id]) # make sure you have this
#task.update_attributes(:done => params["done"])
render :json => { data: "Success", is_done: params[:done] }
end
How to update page content without having to reboot ?
Controller:
def done
#task = Task.find(params[:id]) # make sure you have this
#task.update_attributes(:done => params["done"])
render :json => { data: "Success", is_done: params[:done] }
end
View:
....
<td><%= task.done %></td>
<td><%= check_box_tag 'done', task.id , task.done, :class => "task-check" %></td>
....
<script>
$(".task-check").on('change', function(e){
// removed remote-true. you can preventDefault if you need to but doubt page tries to refresh from a checkbox getting checked. e.preventDefault() if you need it
$.ajax({
type: "POST",
url: '/tasks/done',
type: 'POST',
data: {done: $('.task-check').val()},
}).done(function(ajax_response){
// update whatever you want after it completes
});
});
</script>
Didn't test this but I write these all the time. Let me know if it doesn't work post the payload and I'll figure out what's missing.
If you just want to update the value from 'incomplete' to 'complete', you can simply target the element that's called incomplete. if it has a class of, say, 'task-status' you can target that element and update in the .done part of the function. For instance:
$('.task-status').text('Complete')
should replace what previously said incomplete. If it's a text input you might use .val() instead. If it's just text on the page .text() should work.

Checkbox in index view live updating

I'm currently learning rails and working on what I'm sure is everyone's first rails app, a simple todo list. I need to implement a checkbox next to the items to indicate whether they are complete or not. Each item has a boolean attribute called "completed" in their model. I have found a couple checkbox questions while searching but none explain the syntax very easily in the context of the index view.
Also, I really want the checkbox to work without a submit button. I know I could accomplish something like this using AngularJS's ng-model but I don't think it would be practical to implement angular for such a small thing and I don't know how angular works with rails.
If anyone could give me a pointer in the right direction, it would be greatly appreciated. Here's my index.html.erb for reference.
<h1>
To Do List
</h1>
<table>
<tr>
<% #todo_items.each do |item| %>
<!-- Checkbox here -->
<tc style="<%= 'text-decoration: line-through' if item.completed %>">
<%= link_to item.title, item %>
</tc>
<tc>
<%= item.description %>
</tc>
<tc>
<%= link_to "Edit", edit_todo_item_path(item) %>
</tc>
<tc>
<%= link_to "Delete",item, data:{:confirm => "Are you sure you want to delete this item?"}, :method => :delete %>
</tc>
<hr/>
<% end %>
</tr>
</table>
<p>
<%= link_to "Add Item", new_todo_item_path %>
</p>
This is my way, I don't know this way is right direction or not but this works for me (also different case but same of concept).
views for checkbox
You could put an id item or something into attribute of checkbox for find an object in controller if you send data to controller for get record of object, and you could define if attribute completed of record is true or false:
<%= check_box_tag :completed_item, 1, item.completed? ? true : false, { class: 'name-of-class', data: { id: item.id} } %>
controller
You need two action call set_completed and remove_completed, and also you don't need templates for them, just use format as json:
before_action :set_item, only [:set_completed, :remove_completed, :other_action]
def set_completed
#item.set_completed!
respond_to do |format|
format.json { render :json => { :success => true } }
end
end
def remove_completed
#item.remove_completed!
respond_to do |format|
format.json { render :json => { :success => true } }
end
end
private
def set_item
#item = Item.find params[:id]
end
Model
For set_completed! and remove_completed! you could define in your model
def set_default!
self.update_attributes(:completed => true)
end
def remove_default!
self.update_attributes(:completed => false)
end
routes
resources :address do
collection do
post 'set_completed'
post 'remove_completed'
end
end
Also, you need help JavaScript for handle send request from view to controller event click of checkbox:
jQuery
$(".completed_item").click(function(){
var check = $(this).is(":checked");
if (check == true){
set_completed($(this).attr('data-id'));
} else{
remove_completed($(this).attr('data-id'));
}
});
function set_completed(data_id) {
$.ajax({
type: 'POST',
url: "/items/set_completed",
data: { id: data_id},
dataType: 'json',
success: function(response){
if(response){
}else{
alert('error');
}
}
})
}
function remove_compelted(data_id) {
$.ajax({
type: 'POST',
url: "/items/set_completed",
data: { id: data_id},
dataType: 'json',
success: function(response){
if(response){
}else{
alert('error');
}
}
})
}

Is it possible to refresh partial frequently using Ajax?

In background, I want it to reload and shows the number how many unread messages are there.
I want that without refreshing page. I mean using ajax.
If I had this in menu, how can I refresh only this section every 30 secs?
<li><%= link_to sanitize('<i class="icon-envelope"></i> ') + "received messages" + sanitize(' <span class="badge badge-info">'+current_user.mailbox.inbox(:read => false).count(:id, :distinct => true).to_s+'</span>'), messages_received_path %></li>
messages_controller.rb
def received
if params[:search]
#messages = current_user.mailbox.inbox.search_messages(#search).page(params[:page]).per(10)
else
#messages = current_user.mailbox.inbox.page(params[:page]).per(10)
end
add_crumb 'Messages Received', messages_received_path
#box = 'inbox'
render :index
end
UPDATE:_______________________________
assets/javascript/refresh_messages_count.js
$(document).ready(function () {
// will call refreshPartial every 3 seconds
setInterval(refreshPartial, 3000)
});
function refreshPartial() {
$.ajax({
url: "messages/refresh_part";
})
}
messages_controller.rb
def refresh_part
#message_count = current_user.mailbox.inbox(:read => false).count(:id, :distinct => true)
# get whatever data you need to a variable named #data
respond_to do |format|
format.js {render :action=>"refresh_part.js"}
end
end
views/layouts/_menu.html.erb
<span id="message_received_count"><%= render :partial => "layouts/message_received_count" %></span>
views/layouts/_message_received_count.html.erb
<% if user_signed_in? && current_user.mailbox.inbox(:read => false).count(:id, :distinct => true) > 0 %>
<li><%= link_to sanitize('<i class="icon-envelope"></i> ') + "Received" + sanitize(' <span class="badge badge-info">'+#message_count.to_s+'</span>'), messages_received_path %></li>
<% else %>
<li><%= link_to sanitize('<i class="icon-envelope"></i> ') + "Received", messages_received_path %></li>
<% end %>
views/messages/refresh_part.js.erb
$('#message_received_count').html("#{escape_javascript(render 'layouts/messages_received_count', data: #message_count)}");
You will use setInterval to send the ajax request:
$(document).ready(function () {
// will call refreshPartial every 3 seconds
setInterval(refreshPartial, 3000)
});
// calls action refreshing the partial
function refreshPartial() {
$.ajax({
url: "whatever_controller/refresh_part"
})
}
Then you make an action in a controller like this:
def refresh_part
# get whatever data you need to a variable named #data
respond_to do |format|
format.js
end
end
then you will write a js file named refresh_part.js.haml (you could erb instead of haml).
refresh_part.js.haml would look like this:
$('#part_you_want_to_refresh').html("#{escape_javascript(render 'name_of_partial', data: #data)}");
make sure you set the correct routes in routes.rb.
FYI, refresh_part.js.erb would look like this:
$("#part").html("<%= escape_javascript(render 'partial', data: #data) %>");
instead of:
$('#part').html("#{escape_javascript(render 'partial', data: #data)}");
also, we can use the alias of "escape_javascript" to simplify this:
$("#part").html("<%= j(render 'partial', data: #data) %>");
Yes you can
<html>
<head>
<script type="text/JavaScript">
<!--
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
}
// -->
</script>
</head>
<body onload="JavaScript:timedRefresh(5000);">
<p>This page will refresh every 5 seconds. This is because we're using the 'onload' event to call our function. We are passing in the value '5000', which equals 5 seconds.</p>
<p>But hey, try not to annoy your users too much with unnecessary page refreshes every few seconds!</p>
</body>
</html>
Source: http://www.quackit.com/javascript/javascript_refresh_page.cfm

How to add ajax to jquery-ui slider using ruby on rails 3.2

So I'm following this outdated tutorial on using the jquery-ui slider with rails 3 beta since it's the only one I've found.
My view which has the script
<p>
<p>Showing all stocks between <span id="x_low_selected"><%= #price_range.first %></span> and <span id="x_high_selected"><%= #price_range.last %></span></p>
</p>
<div id="x_slider"></div>
<ul id="x_stock_list">
<%= render 'map' %>
</ul>
<script type="text/javascript">
$(function() {
$("#x_slider").slider( {
range: true,
step: 1,
max: <%= #price_range.last %>,
min: <%= #price_range.first %>,
values: [<%= #price_range.first %>, <%= #price_range.last %> ],
stop: function(event, ui) {
var prices = $('#x_slider').slider('option', 'values');
$('#x_low_selected').html(prices[0]);
$('#x_high_selected').html(prices[1]);
$.ajax({
url: 'http://localhost:3000/users',
type: "GET",
data: { low: prices[0], high: prices[1] },
dataType: 'json'
});
}
});
});
</script>
model method for prices
def self.low_high_prices
[User.minimum(:start), User.maximum(:end)]
end
and the index method in the controller which the ajax should call
def index
#users = User.all
unless params[:low] && params[:high]
#users = User.all
#json = User.all.to_gmaps4rails do |user, marker|
marker.infowindow "<a href=/users/#{user.id}> #{user.name} </a>"
marker.title user.name
end
else
#json = User.where("start >= params[:low] AND end <= params[:high]).to_gmaps4rails do |user, marker|
marker.infowindow "<a href=/users/#{user.id}> #{user.name} </a>"
marker.title user.name
end
end
#price_range = User.low_high_prices
respond_to do |format|
format.html # index.html.erb
format.json { render json: #users }
end
end
Does anyone know why the ajax call isn't being sent to the controller when the slider stops sliding? Not sure if I would be able to use :remote => true because the slider is generated inside the div.
Thanks
Also I am currently using rails 3.2 with ruby 1.9.7
I would guess that your call is going through to the controller, and the controller is returning JSON data.
The problem is that your $.ajax call is doing nothing with the JSON data received.
You need to add a callback function to handle the JSON data passed back in some way in the ajax call:
$.ajax({
url: 'http://localhost:3000/users',
type: "GET",
data: { low: prices[0], high: prices[1] },
dataType: 'json',
success: function (data) {
alert("Success: " + data);
//do something with the data here.
}
});
Also, looking at the controller code, it will only pass back the contents of #users in the JSON data, not the contents of #json or anything else - not sure if that was your intention or not.

Implementing a endless scroll with Rails 3 and Jquery

I'm trying to implementing an endless scroll on my project. I'm using a mix of the Railscast #114 Endless Page and this.
Everything works fine besides a weird behavior when I try to stop sending requests when the page hits its end.
So far I have:
Controller:
def show
#title = Photoset.find(params[:id]).name
#photos = Photoset.find(params[:id]).photo.paginate(:page => params[:page], :per_page => 20)
respond_to do |format|
format.js
format.html
end
end
Show.html.erb:
<% content_for :body_class, '' %>
<%= render 'shared/header' %>
<div id="photos_container">
<div id="photos_header">
<h2><%= #title %></h2>
</div>
<%= render :partial => 'photo', :collection => #photos %>
</div>
<%= render :partial => 'endless_scroll' %>
Javascript (loaded via partial):
<script type="text/javascript">
(function() {
var page = 1,
loading = false,
finish = false;
function nearBottomOfPage() {
return $(window).scrollTop() > $(document).height() - $(window).height() - 200;
}
function finish() {
finish = true;
}
$(window).scroll(function(){
if (loading) {
return;
}
if(nearBottomOfPage() && !finish) {
loading=true;
page++;
$.ajax({
url: '/photosets/<%= params[:id] %>?page=' + page,
type: 'get',
dataType: 'script',
success: function() {
loading=false;
}
});
}
});
}());
</script>
show.js.erb
$("#photos_container").append("<%= escape_javascript(render :partial => 'photo', :collection => #photos) %>");
<% if #photos.total_pages == params[:page].to_i() %>
page.call 'finish'
<% end %>
As you can see, on my show.js.erb I have a page.call that assigns true to the finish variable. This stops the requests.
The wired thing is that it never loads the last page. When #photos.total_pages == params[:page].to_i() instead of just calling the finish function and setting the variable to true, it's also preventing the $("#photos_container").append("<%= escape_javascript(render :partial => 'photo', :collection => #photos) %>"); from running.
It sends the request to the controller, runs the SQL but doesn't append the last page.
If I change the condition to #photos.total_pages < params[:page].to_i() it works, but send an extra request to a page that doesn't exist.
I'd appreciate any help on my implementation. I'm not sure if there's a more adequate (Rails) way to accomplish this.
First of all you can render html from the partial when request is xhr type:
def show
photoset = Photoset.includes(:photos).find(params[:id])
#title = photoset.name
#photos = photoset.photo.paginate(:page => params[:page], :per_page => 20)
if request.xhr?
render '_photo', :layout => false
end
end
Then use ajax call:
$.ajax({
url: '/photosets/<%= params[:id] %>?page=' + page,
type: 'get',
dataType: 'script',
success: function(response) {
$("#photos_container").append(response);
if (response == "") {
//stop calling endless scroll
}
});
});

Resources