How can I control form submit remote with variable?

前端 未结 2 1978
忘了有多久
忘了有多久 2021-01-28 17:07

I want to control when to refresh page (respond_to format.html) and when to toggle buttons (respond_to format.js), by passing local variable to partial used for remote: true (re

相关标签:
2条回答
  • 2021-01-28 17:55

    Wow, I finally solved this one. Whew, lots of investigation, but I learned lots along the way. I'll share my solution here.

    So my scenario is that I'm trying to be DRY, and so I have two partials for "Add to favorites" and "Remove from favorites" buttons. In my event management app, search results page shows events, and initially the "Add to favorites" button partial is rendered. When user clicks button, AJAX form submit replaces that partial with the "Remove from favorites" partial. That way user can toggle between adding to/removing from favorites if they change their mind.

    But I also want to use those "Add to favorites" / "remove from favorites" partials on the user profile page, and favorites index page, and on those pages, when user clicks "Remove from favorites", I don't want the "Add to favorites" button to show up, I want to refresh the page so the list of favorites is minus that removed item. In this case, I simply don't do an AJAX call.

    To achieve this I need a way to control the remote: for the form, true for the AJAX call, false for the HTML (page refresh) call. The following code (only what is relevant shown) is how I did it.

    Hope this helps someone else.

    ----------------- parent partial -----------------

    Here in the parent partial, setting remote_flag: true prevents page refresh through AJAX call, and remote_flag: false would be HTML call, for page refresh.

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

    ------------- add favorite partial ----------------

    The hidden_field :remote_flag allows controller to access via params[:remote_flag].

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

    ------------- remove favorite partial ----------------

    The hidden_field :remote_flag allows controller to access via params[:remote_flag].

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

    ---------------- Favorites controller ----------------

    In the controller, this code allows create.js.erb and destroy.js.erb to access @remote_flag:

    @remote_flag = params[:remote_flag]
    
    
    class FavoritesController < ApplicationController
      before_filter :signed_in_user
    
      def create
        @remote_flag = params[:remote_flag]
        @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 show
        @user = current_user
      end
    
      def destroy
        @remote_flag = true
        @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, remote_flag: @remote_flag })) %>');
    <% 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, remote_flag: @remote_flag })) %>');
    <% end %>
    
    0 讨论(0)
  • 2021-01-28 18:07

    @remote_flag is an instance variable, not the local variable, so it isn't passed to the partial with locals: { user_event: user_event, remote_flag: false } construction. Since it isn't set, it is (by default) nil and it behaves like false in conditional statements. Instead, you should rather use your passed local variable, remote_flag:

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

    and pass variable through locals: {...} construction or set an instance variable explicitly in controller:

    @remote_flag = !!condition
    
    0 讨论(0)
提交回复
热议问题