Is there a way to automate downloading a file in Angular using the browser's built-in download feature?

When I make a request to my webservice to download a zip file, the file content is downloaded secretly and suddenly appears in the download task bar as already fully downloaded (100%).

I am using the following method in Angular:


const endpoint = "http://localhost:8080/download/zip"
this.http.get<Blop>(endpoint, {headers: httpHeaders, responseType: 'blob', reportProgress: true })

This is how I handle the subscription:

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);
  }
})

I noticed that my console.log(...) is only called at the end of the download process. It seems that the browser UI can't detect the download progress until it reaches window.location.href.

Is there a way to force the download to be displayed in the task bar before the transfer is complete, and to track the download progress in the browser? I couldn't find anything related to async blobs or similar methods.

PS: My backend is serving a stream of data, so the issue is not with the backend. When accessing the API directly through the browser, the download progress is visible in the task bar. Here's the snippet from my Spring Boot backend:

    @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)
            }
        }
    }

Answer №1

When it comes to downloading, you have two main options:

  1. Using http.get with msSaveOrOpenBlob (if defined) or createObjectURL
  • You have complete control over the request, process, and errors. For example, you can cancel a request, add headers, and more.
  • The download remains within your app's flow, so refreshing the page will cancel it.
  1. Creating a hidden download link and programmatically clicking on it
  • With this method, you are unable to add headers or show progress/errors easily. There are some workarounds involving setting additional cookies by the backend.
  • This starts as a separate process, meaning you can close your app tab without interrupting the download.

It seems that these two approaches cannot be mixed, and in general, the first option is considered more modern and preferable for small files. However, if you prefer the second approach, you can try the following code snippet:

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)
}

Answer №2

If you're using Angular's HttpClient, the following code snippet should help facilitate file download functionality:

    const apiEndpoint = "http://localhost:8080/download/zip"
    const request = new HttpRequest('GET', apiEndpoint, { observe: 'events', responseType: 'blob' })
    this.http.request(request).subscribe(event => {
      if (event.type === HttpEventType.DownloadProgress) {
        const progress = Math.round(100 * event.loaded / (event.total || 0))
        console.log(progress);
      } else if (event instanceof HttpResponse) {
        const fileBlob = new Blob([event.body as any], { type: 'application/zip' });
        window.location.href = URL.createObjectURL(fileBlob);
      }
    })

Answer №3

If you're looking to save files easily, consider using the ngx-filesaver package.

npm i ngx-filesaver

Simply include the following constructor in your code:

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);
  });
}

To learn more about ngx-file saver package, visit ngx file saver. Additionally, you can check out file saver.js.

Answer №4

Looking at it from a technical standpoint, altering how browsers handle background file downloads is not possible. However, you can track the progress of a download by setting the option observe to events when making an HTTP request. This enables you to not only receive the final response body but also monitor intermediate HTTP events. Subsequently, you have the ability to display your own custom download progress independent of the browser.

Within Angular, there are various types of HTTP events, all falling under the umbrella of HttpEvent. It's important to explicitly include the option reportProgress to receive HttpProgressEvents. The HTTP request will appear as follows:

this.http.get(url, {
  reportProgress: true,
  observe: 'events',
  responseType: 'blob'
})

A helpful guide on implementing this can be found at angular file download progress.

Answer №5

Give this a shot:

$('a#someID').attr({target: '_blank', 
                    href  : 'http://localhost/directory/file.pdf'});

This code snippet makes use of jQuery

Answer №6

Check out this user package: https://www.npmjs.com/package/file-saver

npm i file-saver

To use it in your component, make sure to import the SaveAs method

import { saveAs } from 'file-saver';


saveAs(url, name);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

After utilizing the d3-scale function to declare an object, my developer visual suddenly ceases to function

Upon completing a section of a Power BI tutorial, the developer encountered a visual that displayed nothing but a blank page (despite running correctly). Unable to pinpoint the issue, debugging was initiated. The following test code snippet for debugging w ...

Using Angular2, the autofill data on IOS browsers in Chrome is found to be invalid

I am currently using template driven forms in angular2. The form I have developed is working perfectly on desktop and Android devices, however, I am encountering an issue when autofilling the form on Chrome for iPhone - the form becomes invalid. I also hav ...

Passing asynchronous data from method1 to method2 without impacting the functionality of the script responsible for fetching the asynchronous data in method1

When working with TypeScript, I encountered an issue while trying to invoke an external script called SPCalendarPro within a private method that asynchronously fetches data. The script is invoked in the following manner: private _getSPCalendarPro() { con ...

Utilizing SEO and incorporating special characters like !# in a website's URL

I came across an interesting concept about designing a website that utilizes AJAX to load each page section without compromising SEO. It involved incorporating !# in the URL, similar to the approach adopted by Twitter. However, I've been unable to loc ...

Tips on harnessing the power of PhantomJS and node.js for web scraping

After successfully installing node-phantom using the command npm install node-phantom, I encountered an error when running this code: Cannot find module 'webpage' var webpage = require('webpage').create(), url = "https://www.exampl ...

The navigation bar in React Router is interfering with the loading of other components

Currently, I am in the process of setting up a simple navigation bar that consists of basic buttons without any complex functionality. However, I have encountered an issue where placing the navbar inside the switch prevents other components from loading ...

What is the best way to enable the noWrap feature for a Typography component that is within an Alert or AlertTitle component?

My goal is to have a Typography component truncate overflowing text with an ellipsis. However, I am facing an issue where this doesn't work when the Typography component is nested inside an Alert component. Below is a snippet of the code in question: ...

When attempting to retrieve data saved to req.session with express-session from a different endpoint, the data appears to be

While working on my project with express-session, I encountered a peculiar issue. I am saving the currently logged in user to the session, but when I try to access the currentUser key on the get route, I find that the value is an empty object. Strangely, i ...

Ways to stop the default action in a confirm dialog while using Angular JS

Within my save function, I have the following: $scope.saveData = function () { if (confirm("Are you sure you want to save") === false) { return } // do saving When using the above code and clicking "yes," I encounter an error. Interestin ...

Encountering a problem with the chipGrid feature in Angular Material version

I am currently facing an issue with my angular material chip component. The versions I am using are Angular 16 and Material 16. Here are all my dependencies: "@angular/animations": "^16.0.4", "@angular/cdk": "^16.0.4&quo ...

Ensuring User Data is Current in the UI with Firebase Auth Callbacks

Below is the standard method for setting the user state to currentuser that is returned from onAuthStateChanged. I am looking for a useEffect hook that will be triggered whenever there is an update to the user's information. Unfortunately, I am unable ...

Tips on retrieving a specified string from within an array of strings

I need help extracting the inner string from this array within a string: '["sgrdalal21"]' Can someone provide guidance on how to accomplish this? ...

How to troubleshoot Props not functioning in nextjs-typescript?

I'm having trouble with props in my project and I can't seem to figure it out! Here are the three files. I'm still learning typescript but everything seems fine in the code, yet it's not working! Here is index.tsx file: const Home: ...

Tips for parsing a JSON object efficiently

Javascript var obj = { "name" : ["alex","bob","ajhoge"], "age" : [30,31,33] }; To display the value "alex," you can use: document.write(obj["name"][0]) But how can we filter through 'obj' to retrieve all data like this? html <ul ...

I encountered a parsing issue while trying to compile my Vue project

Issue: The component name "Header" should always consist of multiple words. Fix: Change the component name to a multi-word format according to Vue standards (vue/multi-word-component-names). ...

How to utilize the CSS hover feature within an Angular directive?

Presented here is the default directive. import { Directive, Input, Renderer2, ElementRef } from '@angular/core'; @Directive({ selector: '[newBox]' }) export class BoxDirective { @Input() backgroundColor = '#fff'; con ...

Locating the right selector for adding a div to its parent element in jQuery

I have come across an interesting HTML structure: <div class="dropdownedit"> <div class="dropbtn">textxyz</div> <div class="dropdown-content" style="display: none;"> <div href="#" class="ocond" id="text1">text1</div> &l ...

Challenges with Validating Bootstrap Datepicker Functionality

I need to restrict the datepicker input control to only allow selection of dates from the current date onwards. Despite trying to implement validation using the bootstrap-datepicker library and the following JavaScript code, I am still facing issues: $(& ...

`What can be done if ng-if is not responding?`

I'm facing an issue where I want to display a link <a href> only when a certain condition is met, but the link doesn't show up as expected. I have already attempted to experiment with changing the position of the code (inside or outside of ...

What is the best way to implement animation effects in Angular?

I am currently working on developing an application with Angular animations for a span. After studying the example provided in this StackBlitz Example, I attempted to implement my own animated span. To showcase my progress, I have created a MyStackBlitz. ...