Reputation: 294
I have an app that allows users to like a post. When someone likes the post, the post request works but the view isn't updated unless I refresh the page. I'm stuck on this one. This is what I have so far:
Javascript
$('.favorite').on('click', function() {
var $heart = $(this).find('.fa');
$heart.removeClass('fa-heart-o').addClass('fa-heart');
// POST request to server to create favorite in db
$.post('/favorites', {
favorite: { post_id: $(this).attr('data-id') }
},
function(data) {
console.log(data);
});
});
The controller
def create
post = Post.find_by_id(favorite_params[:post_id])
if current_user.favorite_posts.include? post
render json: {}, status: :bad_request
else
@favorite = current_user.favorites.new(favorite_params)
if @favorite.save
render json: @favorite
else
render json: { errors: @favorite.errors.full_messages }, status: :unprocessable_entity
end
end
end
This is the view
<% if current_user.favorite_posts.include? post %>
<span class="fa fa-heart"> <%= post.favorites.count %></span>
<% else %>
<span class="fa fa-heart-o"> <%= post.favorites.count %></span>
<% end %>
Any help is appreciated. Thanks.
Upvotes: 4
Views: 154
Reputation: 2781
Do this:-
var new_count;
new_count = function() {
# your script
};
$(document).ready(new_count);
$(document).on('page:load', new_count);
This issue seems due to turbolink checkthis
Upvotes: 6
Reputation: 76774
There are two solutions to this:
- Invoke the view change with your in-browser ajax
- Use the Rails UJS functionality to run the view change on the server
I think your biggest problem is you don't have any functionality to change your view upon a successful request. The two options above are what you have to get it working, so I'll detail them for you here:
Ajax
Ajax will send a request for you; you still have to manage its response & functionality:
$.post('/favorites', { favorite: { post_id: $(this).attr('data-id') }},
.done( function(data) {
/* Manipulate your view here */
$("span.fa").text(data);
console.log("Success");
});
You must remember that Ajax is just an asynchronous request. That is, Javascript will act like a micro-browser, sending data to the server on your behalf.
It will then receive a response from the server (presumably containing the data you want)... it's your job to then manipulate your view with this data.
JS
The other method you could use involves the Rails UJS system. That is, you can fire javascript ERB templates after your controller action is fired.
This would give you the ability to manipulate your view as you need, without editing your current javascript:
$.post('/favorites', { favorite: { post_id: $(this).attr('data-id') }}
.done( function(data) { console.log(data); });
#app/controllers/favourites_controller.rb
class FavouritesController < ApplicationController
def create
...
respond_to do |format|
if @favorite.save
format.js #-> invokes /views/favourites/create.js.erb
format.json { render json: @favorite }
else
format.js
format.json { render json: { errors: @favorite.errors.full_messages }, status: :unprocessable_entity }
end
end
You'll then be able to use app/views/favourites/create.js.erb
to manipulate your view:
#app/views/favourites/create.js.erb
$("span.fa").hide();
Upvotes: 2
Reputation: 5668
Instead of
function(data) {
console.log(data);
});
You should update your view. You probably should check for errors, and if there is none, update the content's of your span, using a jQuery selector $( "... span.fa" ).text(new_count)
.
With this approach, you can calculate the value of new_count
as (previous_count_in_the_span
+ 1), but you might want to return a count value in your response, if it won't cause a performance problem.
Upvotes: 2