0

Can you tell me please, how I could remove object before destroy method will be end. When I use next pattern, removing object happen when photo was delete, but it take 1 or 3 or more seconds.

_form(edit action)

<% listing.photos.each do |photo|%>
    <%= image_tag photo.image.thumb, class: 'thumbnail', id: "test"%>
    <%= link_to "remove", photo_path(photo),class: 'btn btn-primary', method: :delete, data: { confirm: 'Are you sure?' }, remote: true %>

destroy.js.erb

$('#test').remove();

How I can use this pattern

_form:

<div id="test_<%= photo.id %>">
  <%= image_tag photo.image.thumb, class: 'thumbnail'%>
  <%= link_to "remove", photo_path(photo),class: 'btn btn-primary', method: :delete, data: { confirm: 'Are you sure?' }, remote: true %>

Destroy.js.erb:

 $('#edit_image_<%= @photo.id %>').remove();
Pardeep Dhingra
  • 3,916
  • 7
  • 30
  • 56

2 Answers2

1

If you want to remove the image from the DOM before its real destroying on server to avoid delay you can apply event.preventDefault() on the 'remove' button click. This will allow you to rewrite the normal behavior of the 'remove' button. Take a look at this example about performing some UI actions before the original event and then triggering it.

Also please notice that it's not a good idea to remove something from UI without being sure it's already removed in general. It's not clear enough for the user. So, maybe it would be better to hide the image at first and in case there will be a server error while destroying it you'll show it again and display some instructive message also.

UPD

Considering following markup

<div id="test_<%= photo.id %>">
  <%= image_tag photo.image.thumb, class: 'thumbnail' %>
  <%= link_to "remove", "#", class: 'remove btn btn-primary', data: { id: photo.id, url: photo_path(photo) } %>
</div>

another option is to rewrite remote: true with separate jQuery.ajax() call.

$('.btn.remove').click(function () {
  var $target = $(this).parents('#test_' + $(this).data('id'));

  $.ajax({
    url: $(this).data('url'),
    method: 'DELETE',
    beforeSend: function() {
      $target.hide() # hiding corresponding image
    },
    error: function () {
      $target.show() # revert hiding on error
      console.log("Sorry! Couldn't remove image.") # log message
    }
  })
})
Community
  • 1
  • 1
vlasiak
  • 348
  • 4
  • 10
  • +1 for using optimistic deletion. You can do the same thing with rails ujs (remote: true) by listening for the `ajax:beforeSend` event. – max Jan 29 '17 at 16:44
0

There is a much cleaner way to do it without a js.erb template:

<div class="photo">
  <%= image_tag photo.image.thumb, class: 'thumbnail'%>
  <%= link_to "remove", photo_path(photo),class: 'destroy btn btn-primary', method: :delete, data: { remote: true, type: 'json', confirm: 'Are you sure?' } %>
<div>

Now just setup an ajax handler:

// app/assets/javascripts/photos.js
$(document).on('ajax:success', '.photo .destroy.btn', function(){
  $(this).parent('.photo').remove();
});

And set your controller to return the correct response code.

class PhotosController
  def destroy
    @photo = Photo.find(params[:id])
    @photo.destroy!

    respond_to do |format|
      format.json do
        head :no_content
      end
    end
  end
end

This keeps your client side logic in app/assets/javascripts where it can be cached and minified instead of spreading it around in a bunch of glorified script tags.

max
  • 96,212
  • 14
  • 104
  • 165
  • I tried this way just now, but when I use '.image .destroy.btn' - it's not working. Only '.destroy'. And when I click on the button - it remove all photos and before it sleep 1-3 second(wait response from server). I have array. <% Listing.photos.each do |photos|%> . Thanks, for your attention.Maybe it has another way? – Alexander Borovoi Jan 27 '17 at 14:27
  • I just noticed that I made a misstake where the class was `photo` and the javascript used `.image`. – max Jan 29 '17 at 16:46