Slater
Slater

Reputation: 827

Open Download link In TypeScript (Angular)

My problem is simple. I have this interface built with Angular. When I click on 1 it opens the popup, and then when I click on 2 it calls a function:

showDownloadLink(ev, name) {
    let config = new MdDialogConfig()
        .textContent('<a href="http://www.google.fr">lol</a>')
        .clickOutsideToClose(false)
        .title('Would you like to delete your debt?')
        .ariaLabel('Lucky day')
        .ok('Please do it!')
        .cancel('Sounds like a scam')
        .targetEvent(ev);
    this.dialog.open(MdDialogBasic, this.element, config)
        .then((ref: MdDialogRef) => {
            ref.whenClosed.then((result) => {
                if (result) {
                    var url = this._Service.getDownloadLink(name);
                    console.log(url);
                    //window.open(url,'Download');
                    //this.downloadURI(url );
                }
                else {
                    this.status = 'You decided to keep your debt.';
                }
            })
        });
}

downloadURI(uri) {
    var link = document.createElement("a");
    link.href = uri;
    link.click();
}

The module used is ng2-material with a "confirm dialog" button.

The var url gives me a good url in the console console.log(url); => when I click on the link shown in the console, it downloads the file well :)

The problem is that the download is not triggered in code.

Edit 1 :

After moving some things-

Dashboard.components.ts :

downloadFile(url,file) {
    this._Service.getDownloadFile(url,file);
}

The downloadFile is called in the show download link like before.

In the _service.ts:

import {Injectable} from "angular2/core";
import {S3Object} from "./s3object";
import {Observable} from "rxjs/Observable";
import {Http, Headers, Response} from "angular2/http";
import "rxjs/Rx";
import {CredService} from "./cred.service";
//mettre les parenthèses !!
@Injectable()
export class Service {

    private serviceUrl = 'url';
    private token;
    private headers = new Headers();
    private credS;

    constructor(private http:Http, private cred:CredService) {
        this.credS = cred;
        this.token = cred.getToken();
        this.headers.append('Authorization', 'bearer ' + this.token);
        this.headers.append('Content-Type', 'application/json');
    }

    getDownloadLink(path:string){
        var opUrl = 'download.json?objectKey='+path;
        var urlRes = "";
        this.http.get(
            this.serviceUrl + opUrl,
            { headers: this.headers }
        )
            .map(res => res.text())
            .subscribe(
                data => urlRes = data,
                err => console.log(err),
                () => console.log(urlRes)
            );

        //console.log(urlRes);
        return urlRes;
    }

    getDownloadFile(url:string, file:string) {
        this.http.get(url).subscribe(
            (response) => {
                var blob = new Blob([response._body], {type: "application/text"});
                var filename = file;
                saveAs(blob, filename);
            });
    } 
}

And a customBrowserXhr.ts file:

import {Injectable} from 'angular2/core';
import {BrowserXhr} from 'angular2/http';

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
    constructor() {}
    build(): any {
        let xhr = super.build();
        xhr.responseType = "blob";
        console.log("it's cool bro ! ");
        return <any>(xhr);
    }
}

Edit 2:

My console Log of the execution of the function ( I replaced the correct url by URL in the code)

test url ddl before : "URL/Desert.jpg?serieofparams"
test name ddl before : Desert.jpg

The function:

downloadFile(url,file) {
    console.log('test url ddl before : ' + url);
    console.log('test name ddl before : ' + file);
    this.http.get(url).subscribe(
        (response) => {
            var blob = new Blob([response._body], {type: "image/jpeg"});
            var filename = file;
            saveAs(blob, filename);
        });
}

But I got this error:

Failed to load resource: the server responded with a status of 404 (Introuvable) http://localhost:8080/context/%22URL/Desert.jpg?serieofparams%22
angular2.dev.js:23740 EXCEPTION: [object Object]

Does anyone have any idea of what is causing this? Is it possible that the routing module does this? On this Plunkr it's working perfectly.

Upvotes: 4

Views: 14644

Answers (2)

Thierry Templier
Thierry Templier

Reputation: 202256

An approach would be to load the image through an AJAX request and then leverage the FileSaver library to open the download dialog.

Here is a sample. You need to extend the BrowserXhr class to set the response type.

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
  constructor() {}
  build(): any {
    let xhr = super.build();
    xhr.responseType = "blob";
    return <any>(xhr);
  }
}

Then you can leverage this class to execute the request to get the image content:

@Component({
  selector: 'download',
  template: `
    <div (click)="downloadFile() ">Download</div>
  `,
  providers: [
    provide(CustomBrowserXhr, 
      { useClass: CustomBrowserXhr }
  ]
})
export class DownloadComponent {
  @Input()
  filename:string;

  constructor(private http:Http) {
  }

  downloadFile() {
    this.http.get(
      'https://mapapi.apispark.net/v1/images/'+this.filename).subscribe(
        (response) => {
          var mediaType = 'application/pdf';
          var blob = new Blob([response._body], {type: mediaType});
          var filename = 'test.pdf';
          saveAs(blob, filename);
        });
    }
}

This override (setting the response type) would only applies for this component (don't forget to remove the corresponding provide when bootstrapping your application) because I set the provider in the providers attribute of the component. The download component could be used like that:

@Component({
  selector: 'somecomponent',
  template: `
    <download filename="'Granizo.pdf'"></download>
  `
  , directives: [ DownloadComponent ]
})

See this answer for more details:

Upvotes: 2

Somnath Mali
Somnath Mali

Reputation: 46

Simple solution would be "getDownloadLink" to return intermediate link which will redirect user to actual link that you want.

var url = this._Service.getDownloadLink(name);
console.log(url);
window.location = url;

Note that in the actual download link, from server side you need to set proper content disposition headers.

Upvotes: 1

Related Questions