I have an Angular app where I need to get the contents of a file from a REST API and the generate a file in the client.
As I can not write a new file in client, I use this question as a workaround.
So basically what it does is create a Blob with the contents and generate a download link, and then simulates a click in the link so that the document gets downloaded.
This is my code:
download(filename) {
this.service
.downloadFile(filename)
.subscribe(data => {
console.log(data.document);
this.downloadFile(data.document, filename);
}, err => this.info = err);
}
this gets the data from the server
private downloadFile(content: string, filename: string) {
const link = document.createElement('a');
link.setAttribute('download', filename);
link.href = this.makeTextFileUrl(content, filename);
document.body.appendChild(link);
// wait for the link to be added to the document
window.requestAnimationFrame(function () {
const event = new MouseEvent('click');
link.dispatchEvent(event);
document.body.removeChild(link);
});
}
this builds the link and simulates the click to download
private makeTextFileUrl(content: string, filename: string): string {
let url = null;
const mime = this.getMimeType(filename);
console.log(mime);
const blob = new Blob([content], { type: mime });
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (url !== null) {
window.URL.revokeObjectURL(url);
}
url = window.URL.createObjectURL(blob);
return url;
}
this generates the url link
private getMimeType(filename: string): string {
if (filename.indexOf('.docx') !== -1) return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
if (filename.indexOf('.doc') !== -1) return 'application/msword';
if (filename.indexOf('.pdf') !== -1) return 'application/pdf';
return 'text/plain';
}
mime type is different depending on the extension
So, this works for plain text files, but for docx files I get an error when I try to open the file and with pdf the file seems to be blank.
I read that for binary files I need to set the responseType to ArrayBuffer for this to work, so I updated my service get call to this
downloadFile(id: string): Observable<any> {
return this.authHttp
.get(`${this.api}/download/${id}`, { responseType: ResponseContentType.ArrayBuffer })
.map(res => {
const data = res.json();
return data;
});
}
but now I get an error when I try to download the file, regardless if it's a txt, pdf or docx file SyntaxError: Unexpected token ≻ in JSON at position 0
Does anyone know how to fix this?
Thanks