Angular 4.3: Getting an arraybuffer with new HttpClient
Solution 1
So Martin has solved my issue:
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;
}
Solution 2
The above works and is an acceptable solution, however seems like a code smell just adding anchor tags to the DOM and faking a click when you can do it in a much cleaner way. We've recently had a similar issue for downloading documents in general from an Angular 5 website in which we have used FileSaver(https://www.npmjs.com/package/file-saver) .
Adding FileSaver using npm install file-saver
and doing the relevant imports you can use the following code to download a file:
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;
}
);
}
This uses the native saveAs
command if it exists and implements some other logic to replicate the functionality if it doesn't.
This may do a similar thing under the hood (i don't really know as haven't had the change to look), but it compartmentalises it in an easy to use third party package that I would hope would be maintained (fingers crossed) without me having to update functionality to cater for newer versions of different packages / browsers.
Luke
Updated on June 29, 2020Comments
-
Luke almost 4 years
I would like to change to the new HttpClient. Until now I handle file downloads the following:
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; }
Changing the respondeType to 'arraybuffer' will result in empty files. Any ideas how to solve it?
-
Drenai almost 3 yearsBasically
file-saver
seems to do the same thing, but it also adds a lot of cross browser checks and fallbacks that cover numerous edge cases👍 github.com/eligrey/FileSaver.js/blob/master/src/FileSaver.js