Peter Andersson
Peter Andersson

Reputation: 2047

Updating Rails view from JS using remote = true

I have this code in a Rails view:

(a little simplified to fit in a question)

<%= link_to "FAV", :action => 'make_fav', 
    remote: true,  data: {old_state: "NOTFAV", 
    product: product.id} %>

which works and calls a method "make_fav" in my controller. This methods updates the database and sets an instance variable @newstate = "FAV"

in make_fav.js.erb I can see that this instance variable is set

<% puts "Newstate is #{@newstate}" %>

in my index.html.erb, I have

<td id='<%= "favourite-#{product.id}" %>' >
  <% if current_user.products.exists?(product.id) %>
      <i class="fa fa-star" %></i>
  <% else %>
      <i class="fa fa-star-o" %></i>
  <% end %>
</td>

Now how should I (in make_fav.js.erb) update the td with id "favourite-#{product.id}" to reflect the @newstate variable?

I have tried things like

<% @key = "#favourite-#{@product.id}" %> 
<% x = "<i class='fa fa-star' id='favourite-#{@product.id}></i>" %>

$('<%= @key %>').html("<%= escape_javascript (x) %>");

but as you can see, I'm at a loss when it comes to javascript...

Basically, I want to update the content to

<i class="fa fa-star" %></i>

if @newstate is "FAV", and else

<i class="fa fa-star-o" %></i>

I feel like I'm close, but would appreciate any help!

Also, if there is a better/more "railsy" way of doing it, I would like to hear about it.

Upvotes: 1

Views: 263

Answers (1)

Alex Santos
Alex Santos

Reputation: 2950

Your reasoning is not too far from the solution. It seems like you are correctly calculating the id of the element you want to find, but you want to update the i element within that ID. So a small change on your make_fav.js.erb could do the trick. Try changing to:

(function() {
  var id = "#favourite-<%= @product.id %> i";
  if ($(id).hasClass('fa-star-o')) {
    $(id).addClass('fa-star').removeClass('fa-star-o');
  } else {
    $(id).addClass('fa-star-o').removeClass('fa-star');
  }
})();

In this solution, we first define the selector of the i you want to find (which is the i within the favourite-id and swap the class (if it was fa-star it goes to fa-star-o and vice versa).

Note that instead of using $(id).hasClass('fa-star-o') in that condition, you should use the new state of the data (I just didn't know how it'd look like your particular case), but the make_fav.js.erb could look like:

(function() {
  var id = "#favourite-<%= @product.id %> i";
  <% if current_user.products.exists?(product.id) %>
    $(id).addClass('fa-star').removeClass('fa-star-o');
  <% else %>
    $(id).addClass('fa-star-o').removeClass('fa-star');
  <% end %>
})();

That would be the preferred way, because you're not relying on the state of UI, but on the state of the data.

Upvotes: 2

Related Questions