gracie catherine
gracie catherine

Reputation: 25

ajax 'delete' button for rails

I am trying to get an ajax 'delete' button to work.

The button is deleting the object from my database, but is not updating the index page. so, the deleted object is still present in index until you refresh the page.

In my view:

<%= link_to "Delete Fabric", delete_fabric_path(fabric), method: :delete, data: { confirm: 'Are you sure?' }, :remote => true, :class => 'delete_fabric', class: "btn btn-primary btn-sm"%>

Routes:

delete "/fabrics/:id" => "fabrics#destroy", as: 'delete_fabric'
get "/fabrics/collection" => "fabrics#index", as: "index_fabrics"

Controller:

def destroy
  @fabric = Fabric.find(params[:id])
  @fabric.destroy

  respond_to do |format|
    format.html { redirect_to index_fabrics_url }
    format.json { head :no_content }
    format.js { render layout: false }
  end
end

destroy.js.erb:

$('.delete_fabric').bind('ajax:success', function() {
  $(this).closest('tr').fadeOut();
});

If anyone has an idea of where I am going wrong, it would be much appreciated! Thanks.

This is the tutorial I was following.

Server logs:

Started DELETE "/fabrics/46" for 127.0.0.1 at 2018-08-17 15:57:22 +0800
Processing by FabricsController#destroy as JS
  Parameters: {"id"=>"46"}
  Fabric Load (1.4ms)  SELECT  "fabrics".* FROM "fabrics" WHERE "fabrics"."id" = $1 LIMIT $2  [["id", 46], ["LIMIT", 1]]
  ↳ app/controllers/fabrics_controller.rb:70
   (0.4ms)  BEGIN
  ↳ app/controllers/fabrics_controller.rb:71
  Fabric Destroy (0.5ms)  DELETE FROM "fabrics" WHERE "fabrics"."id" = $1  [["id", 46]]
  ↳ app/controllers/fabrics_controller.rb:71
   (6.3ms)  COMMIT
  ↳ app/controllers/fabrics_controller.rb:71
  Rendering fabrics/destroy.js.erb
  Rendered fabrics/destroy.js.erb (9.4ms)
Completed 200 OK in 83ms (Views: 30.4ms | ActiveRecord: 8.6ms)

Full view:

<!-- SHOW FABRIC COLLECTION / FABRIC OPTIONS-->
<div class="card-deck">

    <% @fabrics.each do |fabric| %>

        <div class="col-sm-6 col-md-4 col-lg-3">
          <div class="card" style="width: 18rem;">
            <img class="card-img-top" src="<%=fabric.image%>">
            <div class="card-body">
              <h5 class="card-title"><%= fabric.fabric_name%></h5>
              <p class="card-text"><%= fabric.fabric_description%></p>
              <p class="card-text"><%= fabric.printed%></p>


<!--               Listing fibre types -->
              <p class="card-text"><small class="text-muted">Composition: 

                        <% fabric.fibre.each do |fibre| %>
                            <%=fibre %>
                        <%end%>
              </small></p>


<!--               Listing colours -->
              <p class="card-text"><small class="text-muted">Colours: 

                        <% fabric.colour.each do |colour| %>
                            <%=colour %>
                        <%end%>
              </small></p>


<!--               Listing suitable for -->
              <p class="card-text"><small class="text-muted">Suitable For: 

                        <% fabric.suitable_for.each do |item| %>
                            <%=item %>
                        <%end%>
              </small></p>

<!--               Show page button -->
      <%= link_to "Full Details", show_fabrics_path(fabric), class: "btn btn-primary btn-sm" %>

<!--              AJAX DELETE BUTTON IN PROGRESS-->

       <%= link_to "Delete Fabric", delete_fabric_path(fabric), method: :delete, data: { confirm: 'Are you sure?' }, :remote => true, :class => 'delete_fabric'%>

<!--              AJAX DELETE BUTTON -->

            </div>
           </div>
      </div>

    <% end %>

</div>

Full, full view:

<!-- MODEL FOR UPLOAD FABRIC -->


<!-- Button trigger modal -->
</br><button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Add Fabric to collection
</button>


<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Add Fabric</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">



<!-- Form to add fabric -->
<%= form_with scope: :fabrics, url: new_fabrics_path, local: true do |form| %>
    <p>
      <%= form.label :fabric_name %><br>
      <%= form.text_field :fabric_name %>

      <%= form.label :fabric_description %><br>
      <%= form.text_field :fabric_description %>

      <%= form.label :purchased_from %><br>
      <%= form.text_field :purchased_from %>

      <%= form.label :meterage %><br>
      <%= form.select :meterage, (0..500) %>

        <%= form.label :select_fibres %><br>
        <%@fibres.each do |fibre|%>
            <%= form.label fibre %>
            <%= form.check_box :fibre, {multiple: true}, fibre.to_s, nil %></br>
        <% end %>

        <%= form.label :main_fabric_colours %><br>
        <%@colours.each do |colour|%>
            <%= form.label colour %>
            <%= form.check_box :colour, {multiple: true}, colour.to_s, nil %></br>          
        <% end %>

        <%= form.label :suitable_for %><br>
        <%@suitable_for.each do |item|%>
            <%= form.label item %>
            <%= form.check_box :suitable_for, {multiple: true}, item.to_s, nil %></br>      
        <% end %>

        <%= form.label :printed? %><br>
        <%= form.check_box :printed %><br>

      <%= form.submit "Add Fabric" %>
    </p>

<% end %>  
<!-- Form to add fabric -->

      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Add Fabric</button>
      </div>
    </div>
  </div>
</div></br></br>


<!-- MODEL FOR UPLOAD FABRIC -->

<!-- FILTER BAR -->

<% if @filtered == true %>

    <%= form_with scope: :filter, url: filter_fabrics_path, local: true do |form| %>
        <p>
        <%= form.select(:fibre, ['Silk', 'Linen', 'Cotton', 'Bamboo'], {:prompt => "Fibre Type"}) %>
        <%= form.select(:colour, ['Blue', 'Yellow', 'Purple', 'Green'], {:prompt => "Select Colour"}) %>
        <%= form.select(:suitable_for, ['Pants', 'Skit', 'Shirt', 'Skirt'], {:prompt => "Suitable For"}) %>
        <%= form.submit "Filter Results" %> 
        </p>
    <% end %> 

<% else %> 

    <%= form_with scope: :filter, url: filter_fabrics_path, local: true do |form| %>
        <p>
        <%= form.select(:fibre, ['Silk', 'Linen', 'Cotton', 'Bamboo'], {:prompt => "Fibre Type"})%>
        <%= form.select(:colour, ['Blue', 'Yellow', 'Purple', 'Green'], {:prompt => "Select Colour"})%>
        <%= form.select(:suitable_for, ['Pants', 'Skit', 'Shirt', 'Skirt'], {:prompt => "Suitable For"})%>
        <%= form.submit "Filter Results" %> 
        </p>
    <% end %>   

<% end %> 
<!-- FILTER BAR -->

<!-- DISPLAYS CURRENTLY SELECTED FIELDS IF @FILTERED VIEW -->

<p><% if @filtered == true %>

    <% if @selected_fibre != "Fibre Type" %>
       <%= "Filtering by Fibre: #{@selected_fibre} "%>
    <% end %></br>  

    <% if @selected_colour != "Select Colour" %>
       <%= "Filtering by Colour: #{@selected_colour} "%>
    <% end %></br>  

    <% if @selected_suitable_for != "Suitable For" %>
       <%= "Filtering by Project: #{@selected_suitable_for} "%></p>
    <% end %></p>


 <%= link_to "Clear Filters", index_fabrics_path, class: "btn btn-primary btn-sm" %><br><br>
<% end %>  


<!-- SWITCHES STATEMENT BASED ON FILTERED YES/NO-->
<% if @fabrics.length == 0 %>
    <h4> NO SEARCH RESULTS (PROMOTE FABRICS THAT MATCH SEARCH FROM RETAILER) </h4></br>
  <% else %>

    <% if @filtered == true %>
        <h4> OPTIONS FOR YOUR SEWING PROJECT</h4></br>
      <% else %>
        <h4> YOUR FABRIC COLLECTION</h4></br>
    <% end %>

<% end %>


<!-- SHOW FABRIC COLLECTION / FABRIC OPTIONS-->
<div class="card-deck">

    <% @fabrics.each do |fabric| %>

        <div class="col-sm-6 col-md-4 col-lg-3">
          <div class="card" style="width: 18rem;">
            <img class="card-img-top" src="<%=fabric.image%>">
            <div class="card-body">
              <h5 class="card-title"><%= fabric.fabric_name%></h5>
              <p class="card-text"><%= fabric.fabric_description%></p>
              <p class="card-text"><%= fabric.printed%></p>


<!--               Listing fibre types -->
              <p class="card-text"><small class="text-muted">Composition: 

                        <% fabric.fibre.each do |fibre| %>
                            <%=fibre %>
                        <%end%>
              </small></p>


<!--               Listing colours -->
              <p class="card-text"><small class="text-muted">Colours: 

                        <% fabric.colour.each do |colour| %>
                            <%=colour %>
                        <%end%>
              </small></p>


<!--               Listing suitable for -->
              <p class="card-text"><small class="text-muted">Suitable For: 

                        <% fabric.suitable_for.each do |item| %>
                            <%=item %>
                        <%end%>
              </small></p>

<!--               Show page button -->
      <%= link_to "Full Details", show_fabrics_path(fabric), class: "btn btn-primary btn-sm" %>

<!--              AJAX DELETE BUTTON IN PROGRESS-->

       <%= link_to "Delete Fabric", delete_fabric_path(fabric), method: :delete, data: { confirm: 'Are you sure?' }, :remote => true, :class => 'delete_fabric'%>

<!--              AJAX DELETE BUTTON -->

            </div>
           </div>
      </div>

    <% end %>

</div>

Upvotes: 0

Views: 793

Answers (3)

Erowlin
Erowlin

Reputation: 10287

Rolandas solution should helps you resolve your issue.

On the server side, the deletion is properly happening and you're rendering the correct partial (the destroy.js.erb file.)

Additional debugging: Add a console.log($(this).closest('tr')) in your event listener for the ajax success.

Your javascript should looks like that:

console.log('Binding event');
$('.delete_fabric').bind('ajax:success', function() {
  console.log('fading the element: ', $(this).closest('tr')); 
  $(this).closest('tr').fadeOut();
});
  • If you don't see a log in your JS console, it means that you're not listening to the correct event.
  • If you see the console log, look at the element that will be faded-out, and checks it's the Fabric you just destroyed.

Upvotes: 1

Anand
Anand

Reputation: 6531

Add unique id for each fabric record i.e (id="fabric_<%=fabric.id%>")

<!-- SHOW FABRIC COLLECTION / FABRIC OPTIONS-->
<div class="card-deck">
  <% @fabrics.each do |fabric| %>
  <div class="col-sm-6 col-md-4 col-lg-3" id="fabric_<%=fabric.id%>">
    <div class="card" style="width: 18rem;">
      <img class="card-img-top" src="<%=fabric.image%>">
      <div class="card-body">
        <h5 class="card-title"><%= fabric.fabric_name%></h5>
        <p class="card-text"><%= fabric.fabric_description%></p>
        <p class="card-text"><%= fabric.printed%></p>
        <!--Listing fibre types -->
        <p class="card-text"><small class="text-muted">Composition: 
          <% fabric.fibre.each do |fibre| %>
          <%=fibre %>
          <%end%>
          </small>
        </p>
        <!--Listing colours -->
        <p class="card-text"><small class="text-muted">Colours: 
          <% fabric.colour.each do |colour| %>
          <%=colour %>
          <%end%>
          </small>
        </p>
        <!--Listing suitable for -->
        <p class="card-text"><small class="text-muted">Suitable For: 
          <% fabric.suitable_for.each do |item| %>
          <%=item %>
          <%end%>
          </small>
        </p>
        <!--Show page button -->
        <%= link_to "Full Details", show_fabrics_path(fabric), class: "btn btn-primary btn-sm" %>
        <!--AJAX DELETE BUTTON IN PROGRESS-->
        <%= link_to "Delete Fabric", delete_fabric_path(fabric), method: :delete, data: { confirm: 'Are you sure?' }, :remote => true, :class => 'delete_fabric'%>
        <!--AJAX DELETE BUTTON -->
      </div>
    </div>
  </div>
  <% end %>
</div>

In controller:-

def destroy
  @fabric = Fabric.find(params[:id])
  if @fabric.destroy
    flash[:success] = "Fabric deleted successfully!"
  end

  respond_to do |format|
    format.html { redirect_to index_fabrics_url }
    format.json { head :no_content }
    format.js { render layout: false }
  end
end

In destroy.js.erb

<%if flash[:success].present?%>
  $("#fabric_<%=params[:id]%>").fadeOut();
  //$("#fabric_<%=params[:id]%>").remove();
<%end%>

Upvotes: 0

Rolandas Barysas
Rolandas Barysas

Reputation: 360

You're defining class twice:

:class => 'delete_fabric', class: "btn btn-primary btn-sm"

try combining those two:

class: "btn btn-primary btn-sm delete_fabric"

Upvotes: 0

Related Questions