2
votes

I have a event search results page where users can click a "Add to favorites" button.

Clicking the button performs a POST to add the event to the user's favorites. If they search again, they will now see a "Remove from favorites" button instead of an "Add to favorites" button for that event.

Currently in the favorites controller create action I use a respond_to so format.js allows user to stay on that search results page.

But how do I then render the partial for the "Remove from favorites" button, instead of the partial for the "Add to favorites" button.

That way they can click "Remove from favorites" for the item they just favorite if necessary.

Screenshot and code below. Thanks in advance.

screenshot

-------------- search results item renderer ---------------

<div id="add_remove_favorite" class="user_event_info_container">
  <% if (signed_in? && current_user && current_user.id != user_event.user_id) %>
    <%= render partial: "shared/add_remove_favorite", 
      locals: { user_event: user_event } %>
  <% end %>
</div>

------------- shared/_add_remove_favorite.html.erb ---------

<% if current_user.following?(user_event) %>
  <%= render partial: 'shared/remove_favorite', 
    locals: { user_event: user_event } %>
<% else %>
  <%= render partial: 'shared/add_favorite', 
    locals: { user_event: user_event } %>
<% end %>

-------------- shared/_add_favorite.html.erb ----------

<%= form_for(current_user.favorites.build(followed_event_id: user_event.id), remote: true) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites", 
    class: "info_button_small user_event_summary_item" %>
<% end %>

-------------- shared/_remove_favorite.html.erb ------------

<%= form_for(current_user.favorites.find_by_followed_event_id(user_event),
  html: { method: :delete }, remote: true) do |f| %>
  <%= f.submit "Remove from favorites", class: "info_inline_control info_button_small user_event_summary_item" %>
<% end %>

-------------- views/create.js.erb ------------ What should go here? I assume this is where I perform the magic.

-------------- views/destroy.js.erb ------------ What should go here? I assume this is where I perform the magic.

2
DRY!!!!! Since you are new at using js within rails - you should really engage in using what is already in rails. Use Coffee instead of JS - get familiar with it! :)ddavison
Thanks for your response sircapsalot. I will check out Coffee. But I'm wondering in what way it will lead to an answer for this question?Greg Lafrance

2 Answers

1
votes

u need to assign uniq id to the add/remove partial where the form is declared. this can be done using event_id(since the events are listed and u will have uniq events). u can send the event id as a hidden field through the form and use it in the js.erb file to find the partial and replace/modify it.

use the code below in js.erb . the syntax is in haml.

- if @event.favorite? #event is saved as favorite
  $('#event_number_#{event.id}').replaceWith("#{escape_javascript(render(partial: 'shared/remove_favorite', locals: {local_variable: some_variable}))}");
- unless @event.favorite? #event is not fav
  $('#event_number_#{event.id}').replaceWith("#{escape_javascript(render(partial: 'shared/add_favorite', locals: {local_variable: some_variable}))}");

in the 'html' options for 'form_for', u can add

html:{ id: "event_number_#{event.id}", class: 'some class'}

i would prefer using the 'link_to' with 'remote' option rather than a 'form', since i only have to change the link text. the link url is going to be the same and there are only 2 actions 'add' and 'remove' on the event object. the event cant be 'added' to favorite twice. u can set the link id and pass the event id in the params and find the id in the js.erb file and change the link text rather than replacing the partial which would be better. if more data is being submitted using the form(i dont see any other in the provided views), then continue using the form.

1
votes

I solved this, and the following is my working solution, for how to toggle a partial for a button when the button is clicked.

My scenario is a user events application, where the user can search for events matching criteria like dates, title, venue, etc. I have a event search results page where users can click an "Add to favorites" button. When they do that the button should be replaced with a "Remove from favorites" button, in case they changed their mind and don't want that favorite.

My solution uses a respond_to with format.js in the controller action which allows user to stay on that search results page, with no page refresh. Screen shot and only relevant code below.

Hope this helps someone else. Thanks all for your suggestions!

screenshot

---------- portion of search results item code -----------

<div id="add_remove_favorite">
  <% if (signed_in? && current_user && current_user.id != user_event.user_id) %>
    <%= render partial: "shared/add_remove_favorite", 
      locals: { user_event: user_event } %>
  <% end %>
</div>

---- partial to decide if "Add to favorites" or "Remove from favorites" should display ----

<% if current_user.following?(user_event) %>
  <%= render partial: 'shared/remove_favorite', 
    locals: { user_event: user_event } %>
<% else %>
  <%= render partial: 'shared/add_favorite', 
    locals: { user_event: user_event } %>
<% end %>

------------ partial for "Add to favorites" button ----------------

<%= form_for(current_user.favorites.build(followed_event_id: user_event.id), 
  html: { id: "event_number_#{user_event.id}" }, remote: true) do |f| %>
  <div class="hidden"><%= f.hidden_field :followed_event_id %></div>
  <%= f.submit "Add to favorites %>
<% end %>

------------ partial for "Remove from favorites" button ------------

<%= form_for(current_user.favorites.find_by_followed_event_id(user_event),
  html: { id: "event_number_#{user_event.id}", method: :delete }, remote: true) do |f| %>
  <%= f.submit "Remove from favorites %>
<% end %>

-------- FavoritesController with create and destroy actions ---------

class FavoritesController < ApplicationController
  before_filter :signed_in_user

  def create
    @user_event = UserEvent.find(params[:favorite][:followed_event_id])
    current_user.follow!(@user_event)
    respond_to do |format|
      format.html { redirect_to user_path(current_user) }
      format.js
    end
  end

  def destroy
    @user_event = Favorite.find(params[:id]).followed_event
    current_user.unfollow!(@user_event)
    respond_to do |format|
      format.html { redirect_to user_path(current_user) }
      format.js
    end
  end
end

------------- create.js.erb -----------

<% if @current_user.following?(@user_event) %>
  $("#event_number_<%= @user_event.id %>").replaceWith('<%= escape_javascript(render(
    partial: 'shared/remove_favorite', locals: { user_event: @user_event })) %>');
<% end %>

------------- destroy.js.erb ----------

<% if !@current_user.following?(@user_event) %>
  $("#event_number_<%= @user_event.id %>").replaceWith('<%= escape_javascript(render(
    partial: 'shared/add_favorite', locals: { user_event: @user_event })) %>');
<% end %>