jQuery 基本集③~非同期通信(Ajax)~

#jQuery 基本集③~非同期通信(Ajax)~

###非同期通信（Ajax）
リクエスト後にレスポンスが帰ってきた際、ブラウザが再読み込みされること無く通信が行われる通信方法。
非同期通信は英語で"Asynchronous JavaScript + XML"と表現され、略して***Ajax（エイジャックス）***と呼ばれる。
非同期通信ではJavaScriptを利用してリクエストを行う。
###JSON
Java Script Object Notationの略で、データ交換を行うためのデータ記述形式の一種。
キーとバリューの組み合わせでデータを表現する形式。

```js
{name: "taro", created_at: "2020-03-29T5:00:00.000+09:00" content: "JSONとは？", image_url: null, id: 1}
```
通常HTMLをレスポンスとして受け取ると、ブラウザは全てのHTMLを書き換え、画面が再読み込みされる。

**Ajax**では主に**JSONという型でレスポンス**が行われれる。
ブラウザでJavaScriptが動作し、必要なデータのみをサーバからJSON形式で返してHTMLを成形し、ブラウザを書き換える。
この仕組みにより、**ブラウザの一部だけを更新することが可能**になります。

###非同期通信のポイント
「フォームのリクエスト送信」や「aタグのリンク先のページを開く」というHTMLの要素を操作した際に定められている挙動をデフォルトアクションといい、Ajax通信では、JavaScriptのメソッドを利用してリクエストを送るため、**デフォルトアクションを無効にする必要**がある。

非同期通信の場合、JSONのデータをレスポンスとして返す必要があるため、レスポンスするためのJSON形式のデータ（ファイル）を準備する必要がある。

###$.ajaxメソッド
非同期のHTTP通信を行うオブジェクト型。
プロパティはキーとバリューの組み合わせ。

```js

{type: 'POST', url: '/todos.json', data: { todo: { content: todo } }, dataType: 'json' }
```
上記の場合は、通信方法はPOSTで、'/todos.json'というURL（実際のURLもしくはファイル名）に、送信したいデータ内容{ todo: { content: todo（テキストフィールドに入力された値）} }を送信し、さらにサーバから返させる値はjsonデータを指定する、という意味になる。
このように、送信先・送信するデータの種別や内容等、必要最小限のデータ内容をajaxメソッドのオブジェクトのプロパティとして定義し、これをhtml化して形成していく。

少し複雑なのは、オブジェクト型の入れ子になっているdata以降の記述であるが、
todoオブジェクトに定義したcontentプロパティの値（バリュー）を送信したいデータ内容として指定しているだけである。

オブジェクトやプロパティなどについて理解していない方は下記を参照してください。
[ONE PIECEで学ぶオブジェクト](https://qiita.com/ki-ra-co/items/45b0c8cbae41d574f7fe)
　　
上記プロパティの中身は、非同期通信に必要なオプションを設定しているということになる。
<img width="646" alt="スクリーンショット 2020-03-29 5.02.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/602e601e-94ba-368d-1378-c8ee58126e9b.png">



####記述例１(POSTの場合)
今回は下記画像のように入力して送信したテキストを追加していく形とする。
<img width="1334" alt="スクリーンショット 2020-03-29 10.53.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/1c164013-9314-ed3d-4e97-476468a785be.png">

上記画像のhtml.erbファイルはこちら↓

```erb
<div class="contents">
  <% @post.each do |post| %>
    <div class="content">
      <%= post.text %>
    </div>
  <% end %>
</div>

<%= form_for @post do |f| %>
  <%= f.text_area :text %>
  <%= f.submit %>
<% end %>
```

```json.jbuilder
json.text @post.text  
```

上記ファイルに対してjQueryでajax通信を行っていく

```js
function(){
  $(function buildPost(post) { //受け取ったjsonデータをhtmlに変換するメソッドを定義する(今回はbuildPostというメソッド名にしている)。
                               //引数にはサーバから返されたjsonデータの中身が入れられている（今回はpostという引数名にした）。
    var html =`<div class="content">  
                 ${post.text}  
               </div>`
               //テンプレートリテラル `` でhtmlタグを囲んで、変換するhtmlタグを定義し変数化する
                 //json.jbuilderファイルに定義したjsonデータを入れ込むための式展開を記述する。
   
    return html  //htmlファイルを返す
  }

  $('#new_post').on('submit', function(e){  //フォーム送信がされた時のイベントハンドラ（送信ボタンの属性でなくフォーム全体を指定する）
    e.preventDefault();  //フォーム送信時のデフォルトアクションを無効にする
    var formData = new FormData(this);  //フォーム送信されるデータ全てがthisに入れられている
    var url = $(this).attr('action');  //送信先の種別を定義すべく、thisからactionを指定して変数化する(actionには"/post"が該当する)
    $.ajax({  //非同期通信のためにajaxメソッドを定義する
      url: url, //送信先のurlを上記で定義した変数で指定する
      type: "POST", //今回はPOST(サーバを介さないGETもある)
      data: formData, //送信先のurlに指定した「/post」に送信するデータを、上記で定義したデータ内容で指定する
      dataType: 'json', //送信されるデータタイプを指定する
      processData: false, //送信するデータ内容をformDataで指定している場合、送信する内容（形）が決定しているので、クエリ文字に書き換えてしまうと支障を来す虞が出てくるためfalseに指定する必要がある
      contentType: false  //content-typeヘッダを変換せず送信する必要があるのでfalseに指定する
    })
    .done(function(post){  //ajax通信が成功した際の処理を記述していく
      var html = buildPost(post);  //受け取ったjsonデータをhtmlに変換するメソッドを前記しているので、これを利用するために変数化しておく  
      $('.contents').append(html);  //追加先のhtmlタグに、用意したhtmlを追加する
      $('#post_text').val();  //非同期通信でるために、フォームに入力した内容が残ったままになるので、フォームの値を空にする
    })
    .fail(function){  //ajax通信が失敗した際の処理を記述していく
      aleat("error");  //今回はエラーを知らせるアラートを用意しておく
    }
    .always(function){  //ajax通信の成功や失敗に関わらず行う処理を記述していく。
      $('.submit').attr('disabled', false);  //preventDefaultにより送信時のデフォルトアクションが無効にされていることから、「disabled」属性が付いたままでinput要素が無効になっている。
    }                                        //これをfalseにして送信ボタンを再び押すことが出来る様に修復しておく。
  })
});
```

###doneとfail
ajaxメソッドの後につけることで、非同期通信が成功した際/失敗した際に行う処理を書くことができる。
両方とも、ajaxメソッドとセットとなるメソッド。
doneは通信が成功したときに、failは通信が失敗したときに動作する。

####.doneのあとにあるpostという引数について####
doneに定義された成功時のメソッドの引数には**リクエストによって返ってきたレスポンスが代入**される。
（今回は引数名を「post」としている）

####attrメソッド
要素が持つ指定属性の値を返す。
要素が指定属性を持っていない場合、関数はundefinedを返す。

今回のケースでは、イベントが発生した要素のaction属性の値を取得しており、action属性にはフォームの送信先のurlの値が入れらている。

####processDataオプション
デフォルトではtrueになっており、dataに指定したオブジェクトをクエリ文字列(例: msg.txt?b1=%E3%81%8B&b2=%E3%81%8D )に変換する役割があります。
クエリ文字列とは、WebブラウザなどがWebサーバに送信するデータをURLの末尾に特定の形式で表記したものの事です。

####contentTypeオプション
サーバにデータのファイル形式を伝えるヘッダ。
今回、デフォルトでは「text/xml」でコンテンツタイプをXMLとして返している。

ajaxのリクエストがFormDataのときはどちらの値も適切な状態で送ることが可能なため、falseにすることで設定が上書きされることを防ぎます。FormDataをつかってフォームの情報を取得した時には必ずfalseにするという認識で構わない。
他にもあるAjaxのリクエスト送信オプションについては下記を参考。
http://js.studio-kingdom.com/jquery/ajax/ajax

####jbuilder
入力データをJSON形式で出力するテンプレートエンジン。(Railsの場合は初期設定としてgemが入れられている)
jbuilderファイルでは基本的に「**json.KEY VALUE**」という形で書くこと可能。

[jbuilderのドキュメント](https://github.com/rails/jbuilder)

下記はRailsでの場合の記述である。
（ファイルの作成場所は対象のhtmlファイルと同じ階層に作り、**ファイル名の冒頭には紐付くアクション名を指定する**様に気を付ける。）

```views/comments/create.json.jbuilder
  json.text  @comment.text
  json.user_id  @comment.user.id
  json.user_name  @comment.user.nickname
```
左側の「json.〇〇」がjsonデータで使われるデータのタイトル。
「json」については決まり文句だと覚えておきましょう。
「〇〇」の命名については、定義したデータ内容が分かる名前にしておきましょう。
対して右側は、送るデータの内容です。

例題で出していたファイルを引用して解説すると、、、

```json.jbuilder
json.text @post.text  
```
左側に記述した「json.text」がどういう形で使われているのかコンソールを確認してみましょう。
<img width="188" alt="スクリーンショット 2020-03-31 10.52.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/580388/69311475-f8e5-547b-80d7-d81d3e61eb89.png">

json.textの「text」が、コンソール上で確認できるデータ内容（左側）のキーとして使われていますね。
右側の「text4」が、json.jbuilderファイルの右側に記述して定義したデータ内容です。


###$.getJSON()の使い方



指定のURLからJSONデータを受け取るだけであれば、この関数を使えば簡単という感じでしょうか。
他社が提供するAPI等の用意されたデータを取り入れて利用したい時にも使えそうですね。
この処理もajax通信の一つです。

こちらの記事が分かりやすかったです。

[$.getJSON()の使い方](https://techacademy.jp/magazine/25634)
[jQuery リファレンス](http://www.jquerystudy.info/reference/ajax/getJSON.html)
###参考までに
他サイトなどのajax通信で行う処理について記載されている記事には、
「success」や「error」などの処理の記述が見受けられることがある。
[jQueryの公式リファレンス](https://api.jquery.com/jQuery.ajax/)によると、***“success(),error(),complete()はjQuery1.8～非推奨になったため、代わりにdone(),fail(),always()を使うように”***との記述があるのであしからず。

```js
//非推奨パターン

$.ajax({

}).success(function(data){
//ajax通信成功時の処理
}).error(function(data){
//ajax通信失敗時の処理
});
```