ドラックアンドドロップによる投稿内容、非同期削除。　[jQuery, Rails]

## 概要
先日クローゼットアプリ（衣服などの管理をするもの）を作成しました。
ドラックアンドドロップにて投稿内容を削除する機能を実装しました。
該当の箇所に投稿内容をドロップした際に、非同期で削除をするというものです。
備忘録も兼ねて投稿しますので、温かい目で頂けると幸いです:grinning:

こちらが実際の動画です。
![demo](https://user-images.githubusercontent.com/55831482/71306276-91641f00-2421-11ea-82f4-8fb3db571b30.gif)

画像を左下のゴミ箱のアイコンにドロップした際にイベントを発火させ、非同期で削除しております。
画像がドラッグされている間にゴミ箱のアイコンに新たなクラスを付与し、アニメーションのように実装しております。

## 流れ
1. jQuery UI導入
2. viewにカスタムデータを追記
3. jQueryにコード記載  
今回は削除機能の実装ですので、jsonなどcontrollerの追記は必要ありません。

## 1. jQuery UI導入

```rails:Gemfile
gem "jquery-rails"
gem "jquery-ui-rails"
```
```rails:application.js
//= require jquery
//= require jquery_ujs
//= require jquery-ui
```
jQuery UIとはjQueryをベースにしたJavaScriptのライブラリであるため、こちら２つのgemをインストールし、application.jsに追記します。
bundle installをお忘れなく！！

## 2.viewにカスタムデータ追記
```haml:_item.html.haml
.items
  - items.each do |item|
    .item{"data-item_id":"#{item.id}"}
      .item__image
        = image_tag(item.image.to_s) if item.image?
      .item__name
        = item.name
```
 １つ１つのitemにdata属性を付与します。（３行目）
jQueryでイベント発火時にデータを取得出来るようにするためです。

## 3.jQuery
```javascript:item_delete.js
$(function(){
  $(document).on("turbolinks:load", function(){
   //itemを動かすようにする ①
    $(".items").sortable({
    });
    // itemがドロップされた時にイベント発火　②
    $(".trash-box").droppable({
      accept: ".item",
      activeClass: "move-trash",
      drop: function(e, ui){
        e.preventDefault();
        var delete_message = confirm("削除してもよろしいですか？");
        if(delete_message == true){
          //ドロップされたitem要素を取得。jQueryオブジェクトからDOM要素を取り出す
          var delete_item = ui.draggable[0];　③
          //idを取得。
          var delete_ID = ui.draggable.data("item_id");④
          var delete_url = "/items/" + delete_ID;
          $.ajax({ ⑤
            url: delete_url,
            type: "POST",
            data: {id: delete_ID, "_method": "DELETE"},
            dataType: "json"
          })
          .done(function(data){　⑥
            delete_item.remove();
            location.reload();
          })
          .fail(function(){
            alert("エラー");
          })
        }
      }
    })
  });
});
```
順を追って説明します。

**①各itemを動かせるようにします。**
`draggable`でも良いのですが、無作為に動いてしまうため、要素を並び替える`sortable`の方が動きがスムーズだったため`sortable`を使用しています。

*sortableで並び替えた要素の順番を保存する際には、gemのインストールやコントローラーの追記が必要となりますので、今回は割愛させて頂きます。*

**②ゴミ箱のアイコン(".trash-box")に要素がdropされた時にイベントを発火するようにします。**
各オプションについては以下の表をご覧下さい。
コードに沿って説明させて頂くと、
acceptにてitemのdropを受け入れます。itemがdragされている間、`trash-box`に`"move-trash"`というクラスが追加されるという流れです。

[![Image from Gyazo](https://i.gyazo.com/abcdb73fb467eb9674cb1f21df34b1c3.png)](https://gyazo.com/abcdb73fb467eb9674cb1f21df34b1c3)

**③dropされたitemの要素を取得**
jQueryオブジェクトからDOM要素を取り出すため、`ui.draggable[0];`とします。
`delete_item`にdropされたitemのDOM要素が代入されます。

**④dropされた要素のidを取得**
dropされた時に先ほどviewに追記した、`item_id`を取得し、削除する時のパスに代入します。

**⑤ajaxでcontrollerに送る情報を記入**
ここで注意すべきなのは、`data: {id: delete_ID, "_method": "DELETE"}`です。
今回は削除機能なので、HTTPメソッドをDELETEリクエストと宣言する必要があります！

**⑥非同期成功時のイベントを記載**
`delete_item.remove();`で画像をview上から消します。
`location.reload();`でリロードにて、実装完了です:star:


## 終わりに
dropされた要素の取得に苦戦しました、、、。
jQuery UI特有のイベントやオプションがあり、リファレンスを何度も読み返し実装しました。

長くなってしまいましたが、最後まで読んで下さりありがとうございました！:relaxed:
他にこうした方が楽だよ！とかあればコメントください！！
以上、初投稿でした！笑
## 参考文献
https://qiita.com/tsubasaozawa/items/2f4783b47e76dc5a7ed3
http://js.studio-kingdom.com/