简体   繁体   中英

Rails AJAX respond_to not getting JavaScript back

I'm trying to implement an AJAX Acts_As_Votable update as discussed in a few other discussions, but for some reason, the format.js doesn't seem to be firing when I send the AJAX request to update the vote count.

What should happen is that the image changes, but it doesn't. Nothing changes and the page doesn't update.

The vote count is working, though, and if I refresh the page I can see it, but the upvote.js.erb and downvote.js.erb files aren't running at all. So it's working on the backend, the js file that should change the view just doesn't seem to be running.

I've tried the common solutions, like not rendering the layout and changing the order in the respond_to, but nothing seems to be making it work.

Any idea what's wrong?

Here's the code:

Controller Actions

def upvote
  @list.upvote_by current_user
  respond_to do |format|
    format.html { redirect_to :back }
    format.js
  end
end

def downvote
  @list.downvote_by current_user
  respond_to do |format|
    format.html { redirect_to :back }
    format.js
  end
end

View

<div id="upvote" class="like"> <!-- Upvote div! -->
  <%= link_to upvote_list_path(@list), method: :put, class: "btn btn-default btn-sm like", remote: true do %>
    <div id="upvote-button">
      <% if user_signed_in? and current_user.voted_up_on? @list %>
        <%= image_tag("upvote-selected.svg") %>
      <% else %>
        <%= image_tag("upvote-not-selected.svg") %>
      <% end %>
    </div>
    <div id="upvote-count">
      <%= rating(@list) %>
    </div>
  <% end %>
</div>

<div id="downvote" class="dislike"> <!-- Downvote Div -->
  <%= link_to downvote_list_path(@list), method: :put, class: "btn btn-default btn-sm dislike", remote: true do %>
    <div id="downvote-button">
      <% if user_signed_in? and current_user.voted_down_on? @list %>
        <%= image_tag("downvote-selected.svg") %>
      <% else %>
        <%= image_tag("downvote-not-selected.svg") %>
      <% end %>
    </div>
  <% end %>
</div>
</div>

upvote.js.erb (in the views/lists folder)

$('.like').bind('ajax:success', function() {

    $('#upvote-button').text(<%= image_tag("upvote-selected.svg") %>);

});

$('.dislike').bind('ajax:success', function() {

    $('#downvote-button').text(<%= image_tag("downvote-not-selected.svg") %>);

});

downvote.js.erb

$('.like').bind('ajax:success', function() {

    $('#upvote-button').text(<%= image_tag("upvote-not-selected.svg") %>);

});

$('.dislike').bind('ajax:success', function() {

    $('#downvote-button').text(<%= image_tag("downvote-selected.svg") %>);

});

Any help would be greatly appreciated. Thanks!!

You're mixing two things here: rendering JS on an AJAX call and actually executing it.

What happens at the moment is that you're rendering JS but the code that binds the ajax:success event has never actually been executed in the client so the browser doesn't know what to do with the JS response.

First, you need to register the event handler for ajax:success in your regular JS code ( application.js or some other appropriate part of your JS structure). Then you can either just decide to eval the response of the server wholesale - it would then just contain the code doing the text replacement - or even decide to return a JSON structure with data appropriate to your use case (to stay simplistic, a hash with image URLs for both the "like" and "dislike" button).

Okay based on the tips in ma_il's answer, I figured out a much simpler way to do this. I completely missed that my original solution was never running the bind the first time, so thank you for that :). I think I could probably make this even simpler with the JSON suggestion... I just need to figure that out.

First I changed the controller actions a little since I didn't need the HTML:

def upvote
  @list.upvote_by current_user
  respond_to do |format|
    format.js
  end
end

def downvote
  @list.downvote_by current_user
  respond_to do |format|
    format.js
  end
end

Then the upvote.js.erb and downvote.js.erb files look like this (this is the upvote one):

$("#upvote-button").html("<%= escape_javascript( image_tag('upvote-selected.svg') ) %>");
$("#downvote-button").html("<%= escape_javascript( image_tag('downvote-not-selected.svg') ) %>");
$("#upvote-count").html("<%= rating(@list) %>");
$("#num-ratings").html("<%= @list.votes_for.size %> Ratings");

And everything seems to work!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM