質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.35%

  • JavaScript

    11209questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    4890questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • CakePHP

    1940questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

FILE APIでCSVファイルを書き出したいですが、反応がありません。

解決済

回答 2

投稿 2017/12/06 20:28

  • 評価
  • クリップ 0
  • VIEW 58

lovelydai

score 16

こんにちは、いつもお世話になっております。

CSVのインポートとエクスポート機能を作っています。
FILE APIを使ってローカルからファイル中身を読み取ってDBに入れるインポートと、DBにあるデータをCSVファイルに吐き出すエクスポートを実装しようとしてます。インポートはなんとか作り、今はエクスポートの方を使っています。

やりたいのは、Cakehphp3のコントローラーからDBの情報を配列で作り、Ajaxで渡してFILE APIを用いてローカルにダウンロードさせることです。

https://qiita.com/wadahiro/items/eb50ac6bbe2e18cf8813

このリンク先のサンプル2番目の感じです。サンプルのテストは上手く行きましたので、以下のように書いてみましたが、ファイルが生成されず、そのまま最後まで走ってしまいます。
デバッグしてみたら、blobオブジェクトが怪しいかな、と思います。ファイル名やJSON,配列のデータは思い通りに取れていますが、なぜかmsSaveBlob, msSaveOrOpenBlob, else(chrome等用)までひっかからずパースしてしまいます。
どこがおかしいのか、怪しいところや何かヒントがありましたら教えてください。
ソースコードとDebugした画面を添付します。宜しくお願い致します。

値はファイル生成前まではちゃんと取れています。

コンソールに配列とCSVデータを出力してみましたが、問題なさそうです。

コントローラー側では、DBからデータを出してそれをSerializeするだけです。

 public function export()
    {
        if($this->request->is('ajax'))
        {
            $customer_idx = $this->Auth->user('customer_idx');
            $sections = $this->Section->find()->where(['customer_idx' => $customer_idx])
                                            ->select(['section_idx','year','customer_idx','section_code','section_name','section_short','memo','is_used','deleter','deleted'])
                                            ->epilog('FOR UPDATE')
                                            ->toArray();
            if(!empty($sections))
            {                          
                // success
                $results = $sections;
                $this->Flash->success(__('データベースからエクスポートに成功しました。'));
            }
            else
            {
                //failed                
                $results = null;
                throw new exception($e);
                $this->log($e);
                $this->Flash->error(__('エクスポート失敗[DBデータエラー](E30005)'));
            }
            $this->set('result', $results);
            $this->set('_serialize', ['result']);                             
        }   
    }


クライアントの方は、ファイル名を入力してもらい、そのファイル名でCSVファイルを生成したいです。<a>タグのdownload
プロパティ使うということでしたので、CSV出力ボタンを押すと、ファイル名を.arrで追加する形にしました。

<div class="form-group">
  <div class="col-lg-12">
       <?= $this->Form->control('filename', ['class' => 'form-control','label' => 'CSVファイル名', 'type' => 'text', 'required' => 'required', 'id'=>'filename']); ?>
  </div>
</div>

      <div class="form-group" align="center">
          <?= $this->Html->link(
                  '戻る', $referer,
                   ['class' => 'btn btn-success btn-sm', 'type' => 'button']
          ); ?>

      <a id="download" href="#"><button type="button" class="btn btn-primary btn-sm">CSV出力</button></a>


スクリプトの方はこんな感じです。

<script type='text/javascript'>

    $('#download').on('click', function(e){  

        // ファイル名をAタグのDownload属性で追加
        e.preventDefault();  
        var filename = $('#filename').val() + ".csv"; 
        $('#download').attr('download',filename);     

        if(window.File && window.FileReader && window.FileList && window.Blob) 
        {        
            if($('#filename').val()=='')
            {
                alert('CSVファイル名は必ず入力してください。');
                return false;
            }

            if(!confirm('CSVファイルにマスタ情報の出力を行います。本当によろしいですか?'))
            {
                alert('CSVファイル出力をキャンセルしました。');
                return false;
            }
            else
            {
              $.getJSON('../section/export',
                    null,
                    function(data,status){                  
                        // phpから連想配列をとってくる
                        if(status)
                        {   
                            var contents = [];
                            var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);   // UTF-8のBOMコード

                            for(var key in data.result)
                            {
                                contents[key] = [];    //配列の要素数を指定する                                
                                contents[key] = Object.values(data.result[key]); // 連想配列を配列にする。                               
                            }

                            'use strict';
                            var csvContents = CSV.stringify(contents); // CSV化する。

                            // データをファイルとして作る
                            var blob = new Blob([bom,csvContents], { type : 'text/csv;charset=utf-8;' });  

                            if (window.navigator.msSaveBlob) { 
                                window.navigator.msSaveBlob(blob, filename); 
                                window.navigator.msSaveOrOpenBlob(blob, filename);                                 
                            } 
                            else 
                            {
                                $('#download').attr('href',(window.URL || window.webkitURL).createObjectURL(blob, {type: "application/octet-stream"}));                                 
                            }                            
                        }
                        else
                        {
                            alert('DBエラー');        
                            return false;        
                        }
                    })
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • defghi1977

    2017/12/06 20:34

    コードをスクリーンショットで貼り付けるのは可読性の面からおすすめできません. コピペでいいのでコードそのものを掲載して下さい.

    キャンセル

  • defghi1977

    2017/12/06 20:39

    「text/csv;charset=utf-8;」の末尾の;が要らない気がする.「text/csv;charset=utf-8」だと思う

    キャンセル

  • lovelydai

    2017/12/07 08:53

    回答ありがとうございます。コードは下の方にあります、スクリーンショットはデバッグの結果を見ていただくために添付したものです。

    キャンセル

  • defghi1977

    2017/12/07 13:00

    「text/csv;charset=utf-8;」のところを「text/plain」に変えたら動きませんか?csvはブラウザで直接取り扱う形式ではないので気になります.

    キャンセル

回答 2

check解決した方法

0

解決しました。
原因は、やはりイベントの着火タイミングでした。
aリンクのボタンを押してイベントを作り、サーバーからオブジェクトを受け取ってきた時には、もうイベントが終わってしまったのでファイルダウンロードイベントが上手く動かなかったというか、着火されなかったようです。

解決策は、まずaタグのDownloadのコピーをhiddenタイプで作り、hrefのcreatedObjectURLを作った後にclick()イベントを明記しておくことでした。
これでファイルはダウンロードされるようになりました。

また、もう一つの問題があり、それは中身に入れる内容のフォーマットでした。
ということで、何とか解決できましたので、そのソースコードを共有致します。

<!--他の部分は省略です、リンクタグでイベントを作るところです。-->
<a id="download" href="#"><button type="button" class="btn btn-primary btn-sm">CSV出力</button></a>
<a id="download_hidden" href="#"></a>
 $.getJSON(urlPath,
        null,
        function(data,status)
        {                  
                if(status)
                {   
                        var filename = $('#filename').val() + ".csv";
                        $('#download_hidden').attr('download',filename);

                        var contents = [];
                        var bom = new Uint8Array([0xEF, 0xBB, 0xBF]);   // UTF-8のBOMコード

                        for(var key in data.result)
                        {
                            contents[key] = [];    //配列の要素数を指定する
                            // オブジェクト値を文字列に変換する。

                            var temp_var = JSON.stringify(Object.values(data.result[key]),
                            // Nullがある場合は、””に変える。                            
                                function(key, value) 
                                {
                                    if (value === null || value =='')
                                    {
                                        return '""';
                                    }
                                return value;
                                }        
                            );                                
                            // 文字列配列をJSONとして加工する。
                            contents[key] = JSON.parse(temp_var);                                
                        }

                        // File APIのBlobのパラメータに投げるために形を整形する。
                        var csvContents = contents.map(function(l){return l.join(',')}).join('\r\n');
                        console.log("cvsContents = ",csvContents);   

                        // データをファイルとして作る                            
                        var blob = new Blob([bom,csvContents], { type : 'text/csv' });     

                        if (window.navigator.msSaveBlob) 
                        { 
                            window.navigator.msSaveBlob(blob, filename); 
                            // msSaveOrOpenBlobの場合はファイルを保存せずに開ける
                            window.navigator.msSaveOrOpenBlob(blob, filename);
                        }
                        else
                        {
                            var linkObj = document.getElementById("download_hidden");
                            linkObj.href =  window.URL.createObjectURL(blob);
                            linkObj.click();
                        }
                }
         window.URL.revokeObjectURL(blob);
 })

投稿 2017/12/07 19:19

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

すみません誤って回答しました・・・。

投稿 2017/12/07 14:21

編集 2017/12/07 14:23

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • JavaScript

    11209questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    4890questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • CakePHP

    1940questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。