60
63

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 5 years have passed since last update.

CSV や Excel 等のエクスポート処理の終了を検知して JavaScript で何かする方法

Last updated at Posted at 2014-05-01

はじめに

Web アプリでは CSV や Excel、PDF をエクスポートする機能を作ることがそれなりにあるかと思います。その処理の終了後、つまり生成した CSV や Excel データがレスポンスされた時やその後に JavaScript で何らかの処理を実行する簡単な方法を見つけたのでメモしておきます。

ファイルダウンロード完了後に画面遷移などをjavascriptで行う で紹介されている方法を参考にさせてもらっています。

アプリの事前準備

何かのデータを CSV としてエクスポートする以下のような機能が Rails アプリにあるとします(バックエンドは Ruby/Rails である必要はありません。なんであれ基本やることは同じです)

app/controllers/foo_controller.rb
class FooController < ApplicationController
  def export
    csv_data = CSV.generate do |csv|
      # (CSV データを作る処理)
    end

    send_data csv_data, disposition: 'attachment',
                        type: 'text/csv',
                        filename: 'foo.csv'
  end
end

補足. Railsにて検索結果をそのままCSV出力する(やや手抜きで)

続いて、ビューは以下のような感じです。それっぽくするために、抽出条件として年度を指定できる風にしています。

app/views/foo/index.html.erb
<h1>エクスポート</h1>

<%= form_tag foo_export_path do %>
  <p>
    <%= label_tag 'year', '出力年度:' %>
    <%= text_field_tag 'year', 2014 %>
  </p>
  <p>
    <%= submit_tag '実行' %>
  </p>
<% end %>

画面上の "実行ボタン" をクリックすると foo.csv という名前の CSV ファイルがダウンロードされます。

以上でアプリの事前準備は完了です。

本題

では、この機能を以下のようにカスタマイズしてみます。

  • 処理中は "実行" ボタンを使用不可へ
  • 処理終了後に完了メッセージを表示し、 "実行" ボタンを使用可へ

これらを実現するために、アプリを以下のように修正します。

まず、エクスポート処理が終了するときに exported という名前で Cookie を作成します。

app/controllers/foo_controller.rb
class FooController < ApplicationController
  def export
    csv_data = CSV.generate do |csv|
      # (CSV データを作る処理)
    end

    # exported という名前で cookie を作成
    cookies[:exported] = { value: 'yes', expires: 1.minutes.from_now  }

    send_data csv_data, disposition: 'attachment',
                        type: 'text/csv',
                        filename: 'foo.csv'
  end
end

そして、ビューを以下のようにカスタマイズします。

app/views/foos/index.html.erb
<h1>エクスポート</h1>

<div id="message"></div>

<%= form_tag foo_export_path, id: 'form' do %>
  <p>
    <%= label_tag 'year', '出力年度:' %>
    <%= text_field_tag 'year', 2014 %>
  </p>
  <p><%= submit_tag '実行', id: 'button' %></p>
<% end %>

<%# Cookie を扱いやすくするために jquery.cookie.js を使う %>
<%= javascript_include_tag 'jquery.cookie.min.js' %>

<script>
  $('#form').submit(function(e) {
    // 実行ボタンをロックし、ラベルを "処理中..." へ
    $('#button').prop('disabled', true).val('処理中...');

    var intervalId;

    // 1 秒間隔で exported cookie をチェック
    intervalId = setInterval(function() {
      if ($.cookie('exported')) {
        // 実行ボタンをアンロック後ラベルを元に戻す
        $('#button').prop('disabled', false).val('実行');

        // 処理が正常に完了した旨のメッセージを表示
        $('#message').text('正常に終了しました。');

        // ポーリングを停止
        clearInterval(intervalId);
        // フラグをクリア
        $.removeCookie('exported', { path: '/' });
      }
    }, 1000);
  });
</script>

以上です。
流れを簡単に説明すると以下のようになります。

  1. (front) 実行ボタンをクリック
  2. (front) 実行ボタンがロックされ、ラベルも "処理中..." へ
  3. (front) exporeted cookie の有無をチェックする処理を 1 秒間隔でポーリング
  4. (rails) エクスポート処理が終了後 exported cookie を作成
  5. (rails) CSV データのレスポンスとともに cookie もクライアントへ送出
  6. (front) クライアント側exproted cookie が見つかったら↓
  7. (front) 実行ボタンをアンロックし、ラベルも元に戻し、メッセージを画面上に表示
  8. (front) exported cookie を削除

その他、処理中のインジケータを表示させたり、完了後にどこかにリダイレクトさせるなど、工夫次第でいろいろできそうです。

サンプルアプリ

動作確認用として GitHub にサンプルアプリを公開しています。
https://github.com/hidakatsuya/sample-run-any-js-after-download-processing

このアプリは ThinReportsRails4 サンプルアプリ をベースとしています。セットアップ方法は README.md を参考にして下さい。

実行後、 http://localhost:3000/tasks へ移動し、 Print Tasks をクリックすると一覧表の印刷処理が開始します。開始と同時に Print Tasks のラベルが Now Printing... へ変化し、処理完了後に PDF がダウンロードされると同時にラベルが Done!! へ変わります。このラベルの変化をこの記事で紹介した方法で実現しています。

フォーク元の Rails4 Example に対する変更箇所は、この コミット をご覧下さい。

参考

60
63
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
60
63

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?