Sunday, November 24, 2019

How to download file in Angular 7

Sometimes, we want to download files from server, but when search about download file in Angular. There are so much chaos information that make me refused. So, after spending two days to find out about it, I must write something about this topic.
How to download file in Angular 7

Let’s get started.
Understanding about Blob
 A blob has its size and MIME type. Blob data is stored in the memory or file system depending on the browser and blob size.
The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user’s system.
So to download our file from server, we will create object of File that contains Blob object.
Below is the syntax for creating a Blob object:
let blob = new Blob(array, [, options]);
Understanding about HttpClientModule and HttpModule
In version 4.3.x, Angular releases the new HttpClient module has some changes when comparing with traditional Http module with the link.
Interceptors allow middleware logic to be inserted into the pipeline.
Immutable request / response objects.
Progress events for both request upload and response download.
Types, synchronous response body access, including support for JSON body types.
JSON is an assumed default and no longer need to be explicitly parsed.
Request JSON data
  // Http module
  this.http.get(url)
      // extract the data in http response
      .map((response: Response) => response.json() as User)
      .subscribe((data: User) => {
          console.log(data);
      });
  // HttpClient module
  this.http.get(url)
      .subscribe((data: User) => {
          console.log(data);
      });
Request non-JSON data
In HttpClient module, if we need to parse any other types of response like text or blob, then we need to add the responseType in the request.
  // HttpClient module
  this.http.get(url, { responseType: 'blob' })
      .subscribe(data => {
          console.log(data);
  });
  // Http module
  this.http.get(url)
      .map((response: Response) => {
          // response.arrayBuffer()   // returns body as an ArrayBuffer
          // response.blob()          // returns body as a Blob
          return response.text();
      })
      .subscribe((data: string) => {
          console.log(data);
  });
Reading Http res
In Http module, the full response is sent to the client.
  this.http.get(url)
      .subscribe((response: Response) => {
          console.log(response);
      });
In HttpClient module, we need to add observe option to specify which kind of data will be returned to the client. Some values of observe option:
body: return parsed body.
response: returns the full response. (Observable of HttpResponse)
events: returns the full event stream. (Observable of HttpEvent)
Post-request verification and flush based testing framework.
The new HttpClient module requires tslib in runtime, so we have to install it npm install tslib --save, and update system.config.js if we use SystemJS:
  map: {
      ...
      'tslib': 'npm:tslib/tslib.js'
  }
And we need to another mapping if we use SystemJS:
  '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js',
To prepare some modules for downloading excel file
http module
All methods in http module that return an RxJS Observable-based API, so, we need to subscribe.
If we do not subscribe to these observable, nothing will happen.
If we subscribe multiple times to these observalbes, multiple HTTP requests will be triggered.
This particular type of Observable are single value streams. If the Http request is successful, these observables will emit only one value and then complete.
These observables will emit an error if the Http request fail.
  npm install @angular/http@latest
  // In service file
  import { Http } from ''@angular/http;
file-saver module
FileSaver.js is used to save files on the client side, and is perfect for web apps that generates files on the client. If the file is coming from the server, we should to use Content-Diposition attachement response header as it has more cross-browser compatibility.
Disadvantages of file-saver module:
The size of RAM
The max blob size limitation
–> So, we can use alternative way, it is StreamSaver.js.
Installation:
  npm install file-saver --save
  // use for typescript
  npm install @types/file-saver --save-dev
Working with sample project
The followings are the sample project about downloading excel file in Angular.
We can find some other ways to download file. And now, this is the first way to do it.
Below is the service file.
// File.service.ts
import { Injectable } from '@angular/core';
import { Http, ResponseContentType, RequestOptions } from '@angular/http';
@Injectable({
    provideIn: 'root'
})
export class FileService {
    public url = '...';
    constructor(private http: Http) {
        // nothing to do
    }
    download() {
        const options = new RequestOptions({
            responseType: ResponseContentType.Blob
        });
        return this.http.get(url, options);
    }
}
And this is the component file.
import { Component, OnInit } from '@angular/core';
import { saveAs } from 'file-saver';
@Component({
    selector: 'app-parent',
    templateUrl: `
                    <button type="button" (click)="downloadFile();">Download</button>
                 `,
    styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
    fileName = '...';
    constructor(private fileService: FileService) {
        // nothing to do
    }
    ngOnInit() {
        // do something
    }
    downloadFile() {
        // check something
        // ...
        // download file
        this.fileService.download().subscribe(
            res => {
                const blob = new Blob([res.blob()], { type : 'application/vnd.ms.excel' });
                const file = new File([blob], fileName + '.xlsx', { type: 'application/vnd.ms.excel' });
                saveAs(file);
            },
            res => {
                // notify error
            }
        );
    }
}

No comments:

Post a Comment