Reputation: 475
So, when I request my webservice for getting download a zip file, it downloads the file content secretely and all of a sudden, the file appears in the download task bar but already downloaded full (100%)
Using the following angular method:
const endpoint = "http://localhost:8080/download/zip"
this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true })
So here is how I am subscribing:
this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true }).subscribe({
next: data => {
console.log('blocking or not');
const blob = new Blob([data as any], { type: 'application/zip' });
window.location.href = URL.createObjectURL(blob);
}
})
So I noticed my console.log(...)
isn't called until the end of the download, so I suppose that the browser-ui can't detect the download until it reaches window.location.href
.
How to force the download to be shown in the download task bar before the end of the transfert, and watch the download progress in the browser? I coudld not find anything related to async blop or something like that.
PS: my backend is serving a stream of data, so the backend is not the problem. When calling my api directly through the browser, we can see the download progress in the download task bar. Still, if you guys are interested, this is the snippet (spring-boot)
@GetMapping("/download/zip")
fun download(response: HttpServletResponse): StreamingResponseBody {
val file = downloads.download("launcher")
response.contentType = "application/zip"
response.setHeader(
"Content-Disposition",
"attachment;filename=sample.zip"
)
response.setContentLengthLong(file.length())
return StreamingResponseBody { outputStream: OutputStream ->
var bytesRead: Int
val buffer = ByteArray(2048)
val inputStream: InputStream = file.inputStream()
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
}
}
Upvotes: 8
Views: 21296
Reputation: 438
User package https://www.npmjs.com/package/file-saver
npm i file-saver
and then in your component, import the SaveAs method
import { saveAs } from 'file-saver';
saveAs(url, name);
Upvotes: -2
Reputation: 565
Try this:
$('a#someID').attr({target: '_blank',
href : 'http://localhost/directory/file.pdf'});
It uses jQuery
Upvotes: -2
Reputation: 18974
From a technical point of view, you can't change the way browsers behave for receiving a file in the background. Instead, you can calculate the download progress by setting the option observe
to events
while making an HTTP request. In this way, you won't just receive the final response body of the request but also get access to intermediate HTTP events.
After that, you can show your own download progress apart from the browser.
There are multiple kinds of HTTP events in Angular, all consolidated under the type HttpEvent. We also need to explicitly pass the option reportProgress
in order to receive HttpProgressEvents. The HTTP request will eventually look like follows:
this.http.get(url, {
reportProgress: true,
observe: 'events',
responseType: 'blob'
})
You can find a good implementation at angular file download progress.
Upvotes: -1
Reputation: 493
You can simply use this package
npm i ngx-filesaver
and
constructor(private _http: Http, private _FileSaverService: FileSaverService) {
}
onSave() {
this._http.get('yourfile.png', {
responseType: ResponseContentType.Blob // This must be a Blob type
}).subscribe(res => {
this._FileSaverService.save((<any>res)._body, fileName);
});
}
complete doc here ngx file saver and also file saver.js
Upvotes: 0
Reputation: 9486
For download you have 2 ways:
There seems to be no chance of mixing these 2 approaches and in general I would say 1st one is more modern and preferable for small files, however if you are not happy with it try 2nd one (https://stackoverflow.com/a/49917066/4019404):
function download(url) {
const a = document.createElement('a')
a.href = url
a.download = url.split('/').pop()
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
Upvotes: 8
Reputation: 5403
Assuming you are using Angular's HttpClient
, something like this should work:
const endpoint = "http://localhost:8080/download/zip"
const req = new HttpRequest('GET', endpoint, { reportProgress: true, })
this.Http.request(req).subscribe(event => {
if (event.type === HttpEventType.DownloadProgress) {
const percentDone = Math.round(100 * event.loaded / (event.total || 0))
console.log(percentDone);
} else if (event instanceof HttpResponse) {
const blob = new Blob([event.body as any], { type: 'application/zip' });
window.location.href = URL.createObjectURL(blob);
}
})
Upvotes: -1