RailsでAjaxによる非同期通信を実装する練習 ~超簡易Todoアプリの作成~

Railsを勉強して早6週間。
Ajaxによる非同期通信？？？な状況をようやく少し抜け出したため、復習も兼ねて学習した超簡易Todoアプリに機能を追加をしてみました。

### Todoアプリ概要
[![https://gyazo.com/4ef1ee434093b6c44a68a0e04ef11b33](https://i.gyazo.com/4ef1ee434093b6c44a68a0e04ef11b33.gif)](https://gyazo.com/4ef1ee434093b6c44a68a0e04ef11b33)
テキストフィールドに入力し「Create Todo」ボタンを押すとTodoリストが作成できます。これを非同期通信で行っていて、JavaScriptは以下の通りです。

```todo.js
$(function() {

  //todoのcontentをliタグでhtmlに追加
  function buildHTML(todo) {
    var html = $('<li class="todo">').append(todo.content);
    return html;
  }

  // CreateTodoボタンが押されたら発火
  $('.js-form').on('submit', function(e) {
    e.preventDefault();  // submitによるフォームの送信を中止
    // テキストフィールドの中身を取得
    var textField = $('.js-form__text-field');
    var todo = textField.val();
    // Ajax発動!!
    $.ajax({
      type: 'POST',
      url: '/todos.json',  //createアクションへ
      data: {
        todo: {
          content: todo  //取得したテキストフィールドの中身をcontentとして送る
        }
      },
      dataType: 'json'  //もちろんjson形式で!!
    })
    .done(function(data) {
      var html = buildHTML(data);  //返ってきたデータをbuildHTMLに渡す↑↑
      $('.todos').append(html);  //作成したhtmlをビューに追加
      textField.val('');  //テキストフィールドを空に
    })
    .fail(function() {
      alert('error')
    });
  });
});
```
ビューとコントローラーはざっくり以下です。

```index.html.erb
<div class="contents">
  <%= form_for @todo, html: { class: 'form js-form' } do |f|%>
    <%= f.text_field :content, class: 'form__text-field js-form__text-field' %>
    <%= f.submit class: 'form__submit js-submit' %>
  <% end %>
  <ul class="todos">
  </ul>
</div>
```

```todos_controller.rb
class TodosController < ApplicationController
  def index
    @todo = Todo.new
    @todos = Todo.order('created_at ASC')
  end

  def create
    @todo = Todo.new(todo_params)
    if @todo.save
      respond_to do |format|
        format.html { redirect_to :root }
        format.json { render json: @todo }  #jsonで送られてきたら@todoをjsonで返す
      end
    else
      render :index
    end
  end

  private
  def todo_params
    params.require(:todo).permit(:content)
  end
end
```

### doneボタンの追加
追加機能として、todoリストの横にdoneボタンを追加し、doneボタンを押すと「todoリストが青色に変化」＋「doneボタンが削除」されるようにしました。

```todo.js
$(function() {

  //idをtodoレコードのidで指定
  function buildHTML(todo) {
    var html = $(`<li class=todo id=${todo.id}>`).append(todo.content);
    return html;
  }

  $('.js-form').on('submit', function(e) {
    //中略
    $.ajax({
    //中略
    })
    .done(function(data) {
      var html = buildHTML(data);
      $('.todos').append(html);
      //doneボタンをaタグで追加(この時data-idにtodoレコードのidを指定)
      var button = $(`<a href="" class="done-button" data-id=${data.id}>`).append('done');
      $('.todos').append(button);
      textField.val('');
    })
    .fail(function() {
      alert('error');
    });
  });

  //doneボタンをクリックで発火
  $('.todos').on('click', '.done-button', function(e) {
    e.preventDefault();  //aタグのリンクを中止
    $(this).remove();  //doneボタンを削除
    var id = $(this).data('id');  //セットしたtodo.idを取り出す
    $(`#${id}`).addClass('blue');  //関連するtodoリストを青色に変更
  })
});
```
blueクラスの文字色は青で指定

```todos.scss
.blue {
  color: blue;
}
```
### ポイント
簡単にポイントをおさらいしておきます。

#### 動的な要素にイベントを設定する
今回appendで追加したa要素をクリックした時にイベントを設定しました。
このような場合は親要素にイベントを設定する必要があります！
[参照サイト](http://blog.keisuke11.com/webdesign/click-event-after-append/)

#### カスタムデータ属性
html要素にdata-*の形で任意の属性を追加できる！
設定した値はjQueryでdata(),attr()で取得できる！
[参照サイト](http://qiita.com/Kta-M/items/2eda39750abd10df9801)

#### テンプレートレテラル記法
JavaScriptで文字列をバックオート(`)で囲むと、${}内で変数や計算式が使える！
[参照サイト](http://qiita.com/kura07/items/c9fa858870ad56dfec12)

###完成！！
それでは動きをみてみます。
[![https://gyazo.com/0c62664efda19ec385eac78a4ab87cc9](https://i.gyazo.com/0c62664efda19ec385eac78a4ab87cc9.gif)](https://gyazo.com/0c62664efda19ec385eac78a4ab87cc9)
できました！これで夕飯にありつけそうです。
ありがとうございました。