0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

非同期時の送信ボタン制御について

Posted at

記事の内容

非同期での送信ボタン制御を実装する中で色々と躓いたため、備忘録も兼ねて記録として投稿しました。

今回は、XMLHttpRequesを使用して JavaScript から非同期的にデータを送信する方法をご紹介いたします。

完成形

Image from Gyazo

完成形のコード

modelオプションに設定している@pdfは、コントローラで定義しているインスタンス変数になります。
gemwicked_pdfを使用しており、ここではPDFファイルを生成する処理を記述しております。

※ コントローラ、フォーム部分は一部割愛しております。

order_page.html.erb
<%= form_with model: @pdf, url: "#{mypage_history_path}?order_id=#{@order.id}", local: true do |f| %>
  <button type="submit", id='pdf-btn', class="btn btn-primary btn-lg btn-receipt">領収書</button>
<% end %>
order_page.html.erb
<script>
$('form').submit(function(){
  element = $("#pdf-btn")[0]
  element.disabled = true;
  element.innerText = "ダウンロード中";

  const xhr = new XMLHttpRequest();
  xhr.open('GET', this.action);
  xhr.responseType = 'arraybuffer';
  xhr.onload = function() {
    if (this.status === 200) {
      const blob = new Blob([this.response], {type:"application/pdf"});
      const link = document.createElement('a');
      link.href = window.URL.createObjectURL(blob);
      link.download = "<%="ryoshusyo-No#{@order.id}.pdf"%>";
      link.click();
    }
    element.disabled = false;
    element.innerText = "領収書";
  };
  xhr.send(f);
  return false;
});
</script>

実装開始

ここから実装内容を説明していきます。

①多重送信防止の対処

まず初めに、送信ボタンに付与したIDとマッチする要素を取得して変数に格納しています。
その後、多重送信防止のため、disabledを付与して非活性にし、ボタンの表記も変更しています。

element = $("#ryosyusyo-android-pdf-btn")[0]
element.disabled = true;
element.innerText = "ダウンロード中";

XMLHttpRequestオブジェクトの生成

次にブラウザとサーバ間で通信を行うためにXMLHttpRequestオブジェクトを生成しています。

const xhr = new XMLHttpRequest();

③リクエスト方法を設定

HTTPメソッドアクセスする場所を指定します。

xhr.open('GET', this.action);

第1引数には、使用する Httpリクエストメソッドを指定します。
今回は、データを取得するだけなのでGETメソッドを指定しています。

第2引数には、リクエスト先のURLアドレスを指定します。
ここではthis.actionformaction属性値であるURLアドレスを指定しています。

④データ型を指定

レスポンスに含まれているデータの型を指定します。

xhr.responseType = 'arraybuffer';

今回は、バイナリデータを含むJavaScriptArrayBufferをデータ型として指定しています。

⑤PDFファイルのダウンロード

ダウンロードするための処理は下記コードになります。

xhr.onload = function() {
  if (this.status === 200) {
    const blob = new Blob([this.response], {type:"application/pdf"});
    const link = document.createElement('a');
    link.href = window.URL.createObjectURL(blob);
    link.download = "<%="ryoshusyo-No#{@order.id}.pdf"%>";
    link.click();
  }
  element.disabled = false;
  element.innerText = "領収書";
};

1, onloadイベント

onloadメソッドを使用してレスポンスを受け取った後に function 内の処理を実行させています。

xhr.onload = function() {

2, Blobオブジェクトを生成

Blobとは、Binary Large Objectの略でバイナリデータを扱うためのクラスです。

そのBlobを使用するとユーザーに動的にファイルをダウンロードさせることが可能になります。
そのため、まず初めにBlobオブジェクトを生成しています。

if (this.status == 200) {
  const blob = new Blob([this.response], {type:"application/pdf"});

第1引数には、データの配列を設定します。
今回は、xhr変数のresponseに格納されているArrayBufferの配列データを渡しています。

第2引数には、ファイルタイプを指定します。
今回は、PDF形式のファイルをダウンロードするため、type:"application/pdf"としています。

3, ダウンロードリンクを作成

次にBlobデータをダウンロードする処理を実装していきます。

const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "<%="ryoshusyo-No#{@order.id}.pdf"%>";
link.click();
  1. createElement('a')リンクタグを生成し、link変数に格納しています。
  2. URL.createObjectURL()を使用し、引数に先ほど生成したblobオブジェクトを渡すことでオブジェクトURLを生成し、href属性値に格納しています。
  3. ダウンロード属性にファイル名を設定しています。
    今回の場合、ファイル名は「ryoshusyo-No{注文番号}.pdf」となります。
  4. 最後に先ほど生成したリンクタグをclickイベントで発火させることで、PDFファイルをダウンロードしています。

4, 元の状態に戻す

ダウンロードボタンをデフォルトの状態に戻すための記述を行っています。

element.disabled = false;
element.innerText = "領収書";

⑥HTTPリクエストを送信

XMLHttpRequestsendメソッドを使用してajax通信を実行しています。

xhr.send();

ここで、③で設定したHTTPメソッドとリクエスト先URLをもとに、リクエスト送信を行っています。

設定内容 => xhr.open('GET', this.action);

⑦イベント伝播を制御

最後に親要素へのイベント伝播を止めるための記述を行っています。

return false;

終わりに

恥ずかしながら今までXMLHttpRequesを利用したことがなく、初見は何がなんだか分からない状態でした、、
今回記事にしたことで理解は深まりましたが、不明点も多々あり、、。
今後も学びを大切に日々アウトプットしていきます!

参考記事

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?