Angular allows you to easily download zip files by incorporating its built

After spending hours trying to download a zip file using Angular, I encountered an issue where the downloaded file was smaller than the original. I followed guidance from this link on downloading files with Angular2.

I opted not to use the <a> tag directly for security reasons.

service

 downloadFile(filePath: string){
        return this.http
            .get( URL_API_REST + 'downloadMaj?filePath='+ filePath)
            .map(res => new Blob([res], {type: 'application/zip'}))
    }

component

downloadFileComponent(filePath: string){
        this.appService.downloadFile(filePath)
            .subscribe(data => this.getZipFile(data)),
                error => console.log("Error downloading the file."),
                () => console.log('Completed file download.');
    }


getZipFile(data: any){
        var a: any = document.createElement("a");
        document.body.appendChild(a);

        a.style = "display: none";
        var blob = new Blob([data], { type: 'application/zip' });

        var url= window.URL.createObjectURL(blob);

        a.href = url;
        a.download = "test.zip";
        a.click();
        window.URL.revokeObjectURL(url);

    }

rest api

public void downloadMaj(@RequestParam(value = "filePath") String filePath, HttpServletResponse response) {

        System.out.println("downloadMaj");
        File fichierZip = new File(filePath);

        try {
            System.out.println("nom du fichier:" + fichierZip.getName());
            InputStream inputStream = new FileInputStream(fichierZip);

            response.addHeader("Content-Disposition", "attachment; filename="+fichierZip.getName());
            response.setHeader("Content-Type", "application/octet-stream");

            org.apache.commons.io.IOUtils.copy(inputStream, response.getOutputStream());
            response.getOutputStream().flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Can anyone shed light on why the entire file is not being downloaded?

Solved

downloadFile(filePath: string) {
        return this.http
          .get( URL_API_REST + 'download?filePath=' + filePath, {responseType: ResponseContentType.ArrayBuffer})
          .map(res =>  res)
      }
private getZipFile(data: any) {
    const blob = new Blob([data['_body']], { type: 'application/zip' });

    const a: any = document.createElement('a');
    document.body.appendChild(a);

    a.style = 'display: none';    
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = test.zip;
    a.click();
    window.URL.revokeObjectURL(url);

  }

Answer №1

  1. To specify the response type as an array buffer in Angular 5+, you need to assign the value arraybuffer to responseType.

downloadFile(filename: string) {
  return this.http.get(URL_API_REST + 'download?filename=' + filename, {
    responseType: 'arraybuffer'
  });
}

  1. You can enable direct file download by creating a window using the following code:

this.myService.downloadFile(filename).subscribe(data => {
  const blob = new Blob([data], {
    type: 'application/zip'
  });
  const url = window.URL.createObjectURL(blob);
  window.open(url);
});

Answer №2

To enable zip download functionality in Angular, you will need to utilize several plugins:

  1. angular-file-saver.bundle

    This plugin includes Blob.js and FileSaver.js bundled together. Simply follow the instructions to add the necessary dependencies to your controller and module.

    .module('fileSaverExample', ['ngFileSaver'])
    .controller('ExampleCtrl', ['FileSaver', 'Blob', ExampleCtrl]);
    

  2. Include JSZip and JSZipUtils

Ensure that the following files are included: jszip.js, jszip-utils.js, angular-file-saver.bundle.js

var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");

// Once everything is downloaded, initiate the download
zip.generateAsync({type:"blob"}).then(function (blob) { // 1) generate the zip file
FileSaver.saveAs(blob, "downloadables.zip");                          // 2) trigger the download
}, function (err) {
    console.log('err: '+ err);
});

Answer №3

Angular provides a simple way to make service calls with header options, eliminating the need for jsZip-util.

public downloadAndZip(url): Observable<any> {
       const options:any = {
        headers: new HttpHeaders({'Content-Type': 'file type of a specific document'}),
        withCredentials: true,
        responseType:'arraybuffer'
      }; 
        return this.http.get<Content>(url,options);

      }

Answer №4

Whenever I need to download files and save them locally, I make use of the FileSaver library. This handy tool allows me to save data as either a blob or string, using a specified name or default one. Here's an excerpt from its official documentation:

function FileSaver.saveAs(data: string | Blob, filename?: string, options?: FileSaver.FileSaverOptions): void

In my DownloadService.ts file:

downloadFile() {
    return this.http.get(url, { params, responseType: 'arraybuffer', observe: 'response' }).pipe(
        map(res => res)
    );
}

And in my.component.ts:

this.downloadService.downloadFile().subscribe((response: HttpResponse<any>) => {
    if(response.body) {
        let fileName = "download.zip";
        const cDisposition: string = response.headers.get('content-disposition');
        if (cDisposition && cDisposition.indexOf(';filename=') > -1) {
            fileName = cDisposition.split(';filename=')[1];
        }

        const data = new Blob([new Uint8Array(response.body)], {
            type: 'application/octet-stream'
        });
        FileSaver.saveAs(data, fileName);
    }
})

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

Navigate to the previous page

What is the best way to navigate back to the last page in Angular 2? Can it be done like this? this._router.navigate(LASTPAGE); For instance, if page C includes a Go Back button, From Page A to Page C, clicking it will take you back to Page A. Fro ...

Angular version 6 allows for specifying input types as numbers and displaying two decimal digits after the comma

How can I format user input to display as currency with thousand separators in Angular? <input type="number" (ngModelChange)="calculateSum()" (change)="calculateAmount(invoiceQuota)" [ngModel]="invoiceQuota.controls.grossAmount.value"> I have attem ...

Best practices for organizing API Services using TypeScript and Next.js Server Actions

My product-actions/index file contains various server actions such as createProduct and getProductAssets, each of which verifies the user session before processing the request. I am looking for a way to check the session validity only once and then procee ...

Angular 5 is having trouble with VideoJS playback

Recently, I started learning angular 5 and wanted to incorporate videojs into my project. Here is the code snippet I have tried: <video *ngIf="url" id="video" class="video-js vjs-default-skin vjs-big-play-centered vjs-16-9" controls preload="auto"> ...

Tips for binding to a single input box within an ngFor loop

Can anyone lend a hand with some code? I'm working on a straightforward table using ngFor, but I'm facing an issue with input binding. The problem is that all the input fields generated by ngFor display the same value when typing. How can I preve ...

typescript optimizing initial load time

When importing the npm package typescript, it typically takes around 0.3 seconds. Is this considered an acceptable load time? Are there any steps that can be taken to optimize performance? The code snippet in index.js demonstrates the process: import &apo ...

Emphasize the search term "angular 2"

A messenger showcases the search results according to the input provided by the user. The objective is to emphasize the searched term while displaying the outcome. The code snippets below illustrate the HTML and component utilized for this purpose. Compon ...

Steps to resolve the issue of "SVG Not defined" during JEST unit testing

Currently, I am in the process of setting up a unit test case for a function within a TypeScript class. This particular class relies on svg.js. However, when attempting to run the unit test with Jest, an error is thrown stating that SVG.extend or SVG is no ...

Exception occurred when trying to map JSON while making a POST request with a request payload

My controller has the specified contract --- @RequestMapping(value="/api/devices/certs",method = RequestMethod.POST,consumes={"application/json","application/xml"}) public String submitCertificate(@RequestBody Certificate certificate){ Syste ...

Issue ( Uncaught TypeError: Trying to access a property of undefined ('data') even though it has been properly defined

One of my custom hooks, useFetch, is designed to handle API data and return it as a state. useFetch: import { useState, useEffect } from "react"; import { fetchDataFromApi } from "./api"; const useFetch = (endpoint) => { const [d ...

Utilizing a personalized URL path in Spring Boot and Maven for backend responses leads to a whitelabel error

I am currently working on two separate projects, one being a projectApi (backend developed in Spring) and the other a projectUi (frontend developed in Angular). To combine these two projects into a single jar for production, I am using the maven-resource-p ...

What are the recommended guidelines for using TypeScript effectively?

When facing difficulties, I have an array with functions, such as: this._array = [handler, func, type] How should I declare this private property? 1. Array<any> 2. any[] 3. T[] 4. Array<T> What is the difference in these declarations? ...

Is it possible to configure a unique Bearer Access Token in the "angular-oauth2-oidc" library?

For my Facebook login, I have set up a custom endpoint where the client sends the Facebook access token. In my Ionic App, I use the '@ionic-native/facebook/ngx' package to retrieve this token. Within a Laravel Json API controller, I utilize Soci ...

Redirect all traffic in Node.js/Express to an Angular 2 page

Currently working on a project using Angular 2, Node.js, and Express. Encountering an issue with my routes file when using a wildcard. Whenever I try to access a page other than / (such as /test), it throws the error message: ReferenceError: path is no ...

Refreshing the page does not trigger Angular callHooks

Encountering an issue with the proper invocation of F5 button or directive call URL from the address bar resulting in ngOnInit not being triggered correctly. Using a debugger to analyze the situation, it was noticed that callHook is not initiated after ngO ...

Why is Axios not being successfully registered as a global variable in this particular Vue application?

Recently, I have been delving into building a Single Page Application using Vue 3, TypeScript, and tapping into The Movie Database (TMDB) API. One of the hurdles I faced was managing Axios instances across multiple components. Initially, I imported Axios ...

No value is returned when webResource.get is called with the String class

After developing a Jersey client program to access a REST web service that returns XML, I encountered an issue. Client client = Client.create(); WebResource webResource = client.resource("http://xyz:abc/myRestservice/getval"); Despite not receiving any e ...

retrieve the preferred item data from the local storage

Having trouble retrieving favorite items from my list item app using Ionic 4. Although my JSON data is added to local storage, I am unable to retrieve the data properly. favourite.service.ts getAllFavoriteItems(){ return this.storage.get("object"); ...

Simple method to determine if a variable belongs to an enumeration

Among the numerous discussions on this topic, none seem to focus on developing a versatile function. This function should take an enum and a variable as input, check if the variable is part of that enum, and update the variable type if it is. I have made ...

Angular (4, 5, 6, 7) - An easy guide to implementing slide in and out animations using ngIf

How can you implement a basic sliding animation in Angular4 to show and hide a container element? For example: <div *ngIf="show"> <!-- Content --> </div> Slide the content in (similar to jQuery's slideDown() method) from top t ...