web-dev-qa-db-ja.com

Angular 4.3:新しいHttpClientで配列バッファを取得する

新しいHttpClientに変更したいと思います。これまでは、ファイルのダウンロードを次のように処理します。

getXlsx (): Observable<any> {
    return this.http.get('api/xlsx', {
      responseType: ResponseContentType.ArrayBuffer, // set as ArrayBuffer instead of Json
    })
    .map(res => downloadFile(res, 'application/xlsx', 'export.xlsx'))
    .catch(err => handleError(err));
  }

export function downloadFile(data: any, type: string, filename: string): string {
  const blob = new Blob([data._body], { type });
  const url = window.URL.createObjectURL(blob);

  // create hidden dom element (so it works in all browsers)
  const a = document.createElement('a');
  a.setAttribute('style', 'display:none;');
  document.body.appendChild(a);

  // create file, attach to hidden element and open hidden element
  a.href = url;
  a.download = filename;
  a.click();
  return url;
}

ResponseeTypeを 'arraybuffer'に変更すると、ファイルが空になります。それを解決する方法はありますか?

5
Luke

マーティンは私の問題を解決しました:

getXlsx (): Observable<any> {
    return this.http.get('api/xlsx', {
      responseType: 'blob' // <-- changed to blob
    })
    .map(res => downloadFile(res, 'application/xlsx', 'export.xlsx'))
    .catch(err => handleError(err));
  }

export function downloadFile(blob: any, type: string, filename: string): string {
  const url = window.URL.createObjectURL(blob); // <-- work with blob directly

  // create hidden dom element (so it works in all browsers)
  const a = document.createElement('a');
  a.setAttribute('style', 'display:none;');
  document.body.appendChild(a);

  // create file, attach to hidden element and open hidden element
  a.href = url;
  a.download = filename;
  a.click();
  return url;
}
8
Luke

上記は機能し、受け入れられる解決策ですが、コードに臭いがアンカータグをDOMに追加し、はるかにクリーンな方法でクリックできるように見せかけるように見えます。最近、Angular 5のWebサイトからFileSaver( https://www.npmjs.com/package/ file-saver )。

npm install file-saverを使用してFileSaverを追加し、関連するインポートを実行すると、次のコードを使用してファイルをダウンロードできます。

getDocument(document: Document) {
    let headers = new HttpHeaders(); // additional headers in here

    return this._http.get(url, {
        headers: headers,
        responseType: "blob" // this line being the important part from the previous answer (thanks for that BTW Martin) 
    }).map(
        res => {
            var x = res;
            if (res) {
                let filename = documentName;
                saveAs(x, filename);
            }
            return true;
        },
        err => {
            return true;
        }
    );
} 

これは、存在する場合はネイティブのsaveAsコマンドを使用し、存在しない場合は機能を複製する他のロジックを実装します。

これは、フードの下で同様のことを行う可能性があります(見た目の変更がなかったので、実際にはわかりません)が、使いやすいサードパーティのパッケージにコンパートメント化され、維持されることを期待しています(フィンガークロス)。異なるパッケージ/ブラウザーの新しいバージョンに対応するために機能を更新する必要はありません。

1
chunkydigits