31
votes

I'm trying to provide a pdf download from within an angular 2 app...

this code works:

    var reportPost = 'variable=lsdkjf';

    var xhr = new XMLHttpRequest();

    xhr.open("POST", "http://localhost/a2/pdf.php", true);
    xhr.responseType = 'blob';
    xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    xhr.onreadystatechange = function() {//Call a function when the state changes.
        if(xhr.readyState == 4 && xhr.status == 200) {
            var blob = new Blob([this.response], {type: 'application/pdf'});
            saveAs(blob, "Report.pdf");
        }
    }

    xhr.send(reportPost);

but i would have liked to use angular 2's built-in Http client.

a little research:

and some test code:

    var headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');

    this.http.post('http://localhost/a2/pdf.php', reportPost,  {
        headers: headers
        })
        .retry(3)
        // .map( (res:any) => res.blob() ) // errors out
        .subscribe(
          (dataReceived:any) => {
            var blob = new Blob([dataReceived._body], {type: 'application/pdf'});
            saveAs(blob, "Report.pdf");
          },
          (err:any) => this.logError(err),
          () => console.log('Complete')
        );

ps. the saveAs function comes from here: https://github.com/eligrey/FileSaver.js

3
Seems like the blob()-method isn't implemented yet. See github.com/angular/angular/blob/master/modules/angular2/src/…. An issue tracking the implementation status can be found here: github.com/angular/angular/issues/2803Larrifax
How in the world did you get "saveAs" to work? I've installed the module, installed the typings, and still get "no such function: saveAs" when I run it.. sooooo annoying... how do you include it in the typescript code? (i use webpack, still haven't figured it out)Spock
i've just been ignoring the error from the TS compiler. it still compiles... sloppy huh?ryanrain

3 Answers

53
votes

With the release of Angular2 final we can define for example a service:

@Injectable()
export class AngularService {

    constructor(private http: Http) {}

    download(model: MyModel) { //get file from service
        this.http.post("http://localhost/a2/pdf.php", JSON.stringify(model), {
            method: RequestMethod.Post,
            responseType: ResponseContentType.Blob,
            headers: new Headers({'Content-Type', 'application/x-www-form-urlencoded'})
        }).subscribe(
            response => { // download file
                var blob = new Blob([response.blob()], {type: 'application/pdf'});
                var filename = 'file.pdf';
                saveAs(blob, filename);
            },
            error => {
                console.error(`Error: ${error.message}`);
            }
        );
    }
}

This service will get the file and then serve it to an user.

Example for zip file: How to use JAX-RS and Angular 2+ to download a zip file

16
votes

With @4.3, @5 and HttpClientModule, I ended up doing:

this.http.post(`${environment.server}/my/download`,
                data, 
                {responseType: 'blob', observe: 'response'})
              .map( res => ({content: res.body, 
                             fileName: res.headers.get('content-filename')}));
1
votes

See here: https://stackoverflow.com/a/45666313/4420532

return this._http.get('/api/images/' + _id, {responseType: 'blob'}).map(blob => {
  var urlCreator = window.URL;
  return this._sanitizer.bypassSecurityTrustUrl(urlCreator.createObjectURL(blob));
})