it-swarm.com.de

Wie lade ich eine Datei mit Angular2 herunter?

Ich habe eine WebApi/MVC-App, für die ich einen angle2-Client entwickle (um MVC zu ersetzen). Ich habe einige Probleme zu verstehen, wie Angular eine Datei speichert.

Die Anfrage ist in Ordnung (funktioniert gut mit MVC, und wir können die empfangenen Daten protokollieren), aber ich kann nicht herausfinden, wie die heruntergeladenen Daten gespeichert werden sollen (meistens folge ich derselben Logik wie in diesem Beitrag ). Ich bin sicher, es ist dumm einfach, aber ich fasse es bisher einfach nicht.

Der Code der Komponentenfunktion befindet sich unten. Ich habe verschiedene Alternativen ausprobiert, der Blob-Weg sollte der Weg sein, den ich verstanden habe, aber es gibt keine Funktion createObjectURL in URL. Ich kann nicht einmal die Definition von URL in window finden, aber anscheinend existiert sie. Wenn ich das FileSaver.js Modul benutze bekomme ich den gleichen Fehler. Ich denke, das ist etwas, was sich in letzter Zeit geändert hat oder noch nicht implementiert ist. Wie kann ich das Speichern der Datei in A2 auslösen?

downloadfile(type: string){

    let thefile = {};
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(data => thefile = new Blob([data], { type: "application/octet-stream" }), //console.log(data),
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    let url = window.URL.createObjectURL(thefile);
    window.open(url);
}

Der Vollständigkeit halber befindet sich der Dienst, der die Daten abruft, unten, aber das einzige, was er tut, ist, die Anforderung auszugeben und die Daten ohne Zuordnung weiterzuleiten, wenn sie erfolgreich ist:

downloadfile(runname: string, type: string){
   return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .catch(this.logAndPassOn);
}
101
rll

Das Problem ist, dass das Observable in einem anderen Kontext ausgeführt wird. Wenn Sie also versuchen, die URL var zu erstellen, haben Sie ein leeres Objekt und nicht den gewünschten Blob.

Eine der vielen Möglichkeiten, dies zu lösen, ist folgende:

this._reportService.getReport().subscribe(data => this.downloadFile(data)),//console.log(data),
                 error => console.log('Error downloading the file.'),
                 () => console.info('OK');

Wenn die Anfrage fertig ist, ruft sie die Funktion "downloadFile" auf, die wie folgt definiert ist:

downloadFile(data: Response) {
  const blob = new Blob([data], { type: 'text/csv' });
  const url= window.URL.createObjectURL(blob);
  window.open(url);
}

der Blob wurde perfekt erstellt und daher die URL var. Wenn das neue Fenster nicht geöffnet wird, prüfen Sie, ob Sie bereits 'rxjs/Rx' importiert haben.

  import 'rxjs/Rx' ;

Ich hoffe das kann dir helfen.

115

Versuchen Sie this !

1 - Installieren Sie Abhängigkeiten für das Popup für das Speichern/Öffnen von Dateien

npm install file-saver --save
npm install @types/file-saver --save

2- Erstellen Sie einen Dienst mit dieser Funktion, um die Daten zu erhalten

downloadFile(id): Observable<Blob> {
    let options = new RequestOptions({responseType: ResponseContentType.Blob });
    return this.http.get(this._baseUrl + '/' + id, options)
        .map(res => res.blob())
        .catch(this.handleError)
}

3- In der Komponente den Blob mit 'file-saver' parsen

import {saveAs as importedSaveAs} from "file-saver";

  this.myService.downloadFile(this.id).subscribe(blob => {
            importedSaveAs(blob, this.fileName);
        }
    )

Das funktioniert bei mir!

62
Hector Cuevas

Wenn Sie in der Anforderung keine Header hinzufügen müssen, können Sie zum Herunterladen einer Datei in Angular2 Folgendes tun:

window.location.href='http://example.com/myuri/report?param=x';

in Ihrer Komponente.

27
surfealokesea

Wie von Alejandro Corredor erwähnt, handelt es sich um einen einfachen Bereichsfehler. Die Variable subscribe wird asynchron ausgeführt, und die Variable open muss in diesem Kontext platziert werden, damit das Laden der Daten abgeschlossen ist, wenn der Download ausgelöst wird.

Es gibt zwei Möglichkeiten, dies zu tun. Da die Dokumente empfehlen, kümmert sich der Dienst darum, die Daten abzurufen und abzubilden:

//On the service:
downloadfile(runname: string, type: string){
  var headers = new Headers();
  headers.append('responseType', 'arraybuffer');
  return this.authHttp.get( this.files_api + this.title +"/"+ runname + "/?file="+ type)
            .map(res => new Blob([res],{ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }))
            .catch(this.logAndPassOn);
}

Dann abonnieren wir für die Komponente nur die zugeordneten Daten und behandeln diese. Es gibt zwei Möglichkeiten. Die erste, wie im ursprünglichen Beitrag vorgeschlagen, erfordert jedoch eine kleine Korrektur, wie von Alejandro festgestellt:

//On the component
downloadfile(type: string){
  this.pservice.downloadfile(this.rundata.name, type)
      .subscribe(data => window.open(window.URL.createObjectURL(data)),
                  error => console.log("Error downloading the file."),
                  () => console.log('Completed file download.'));
  }

Die zweite Möglichkeit wäre, FileReader zu verwenden. Die Logik ist die gleiche, aber wir können explizit darauf warten, dass FileReader die Daten lädt, die Verschachtelung vermeidet und das asynchrone Problem löst.

//On the component using FileReader
downloadfile(type: string){
    var reader = new FileReader();
    this.pservice.downloadfile(this.rundata.name, type)
        .subscribe(res => reader.readAsDataURL(res), 
                    error => console.log("Error downloading the file."),
                    () => console.log('Completed file download.'));

    reader.onloadend = function (e) {
        window.open(reader.result, 'Excel', 'width=20,height=10,toolbar=0,menubar=0,scrollbars=no');
  }
}

Hinweis: Ich versuche, eine Excel-Datei herunterzuladen, und obwohl der Download ausgelöst wird (damit wird die Frage beantwortet), ist die Datei beschädigt. Siehe die Antwort zu diesem Beitrag für Vermeidung der beschädigten Datei.

17
rll

Dies ist für Leute, die mit HttpClient und Dateisparer nach Möglichkeiten suchen:

  1. Installieren Sie den Datei-Saver

npm install file-saver --save

npm install @ types/file-saver --save

API-Serviceklasse:

export() {
    return this.http.get(this.download_endpoint, 
        {responseType: 'blob'});
}

Komponente:

import { saveAs } from 'file-saver';
exportPdf() {
    this.api_service.export().subscribe(data => saveAs(data, `pdf report.pdf`));
}
17
Justin

Laden Sie die * .Zip-Lösung für Winkel 2.4.x herunter: Sie müssen ResponseContentType von '@ angle/http' importieren und ResponseType in ResponseContentType.ArrayBuffer ändern (standardmäßig ResponseContentType.Json).

getZip(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
 let headers = this.setHeaders({
      'Content-Type': 'application/Zip',
      'Accept': 'application/Zip'
    });

 return this.http.get(`${environment.apiUrl}${path}`, { 
   headers: headers, 
   search: params, 
   responseType: ResponseContentType.ArrayBuffer //magic
 })
          .catch(this.formatErrors)
          .map((res:Response) => res['_body']);
}
15
Alex Dzeiko

Wie wäre es damit?

this.http.get(targetUrl,{responseType:ResponseContentType.Blob})
        .catch((err)=>{return [do yourself]})
        .subscribe((res:Response)=>{
          var a = document.createElement("a");
          a.href = URL.createObjectURL(res.blob());
          a.download = fileName;
          // start download
          a.click();
        })

Ich könnte damit umgehen.
kein zusätzliches Paket erforderlich.

14
harufumi.abe

Das Herunterladen von Dateien über ajax ist immer ein schmerzhafter Prozess, und meiner Meinung nach ist es für Server und Browser am besten, diese Arbeit der Inhaltstypen auszuhandeln.

Ich denke es ist am besten zu haben 

<a href="api/sample/download"></a> 

es zu tun. Dies erfordert nicht einmal das Öffnen neuer Fenster und ähnliches.

Der MVC-Controller wie in Ihrem Beispiel kann wie folgt aussehen:

[HttpGet("[action]")]
public async Task<FileContentResult> DownloadFile()
{
    // ...
    return File(dataStream.ToArray(), "text/plain", "myblob.txt");
}
9
Bharat Raj

Für neuere Winkelversionen:

npm install file-saver --save
npm install @types/file-saver --save


import {saveAs} from 'file-saver/FileSaver';

this.http.get('endpoint/', {responseType: "blob", headers: {'Accept': 'application/pdf'}})
  .subscribe(blob => {
    saveAs(blob, 'download.pdf');
  });
8
Tobias Ernst

Ich teile die Lösung, die mir geholfen hat (jede Verbesserung wird sehr geschätzt)

Auf Ihrem service 'pservice':

getMyFileFromBackend(typeName: string): Observable<any>{
    let param = new URLSearchParams();
    param.set('type', typeName);
    // setting 'responseType: 2' tells angular that you are loading an arraybuffer
    return this.http.get(http://MYSITE/API/FILEIMPORT, {search: params, responseType: 2})
            .map(res => res.text())
            .catch((error:any) => Observable.throw(error || 'Server error'));
}

Komponente Teil:

downloadfile(type: string){
   this.pservice.getMyFileFromBackend(typename).subscribe(
                    res => this.extractData(res),
                    (error:any) => Observable.throw(error || 'Server error')
                );
}

extractData(res: string){
    // transforme response to blob
    let myBlob: Blob = new Blob([res], {type: 'application/vnd.oasis.opendocument.spreadsheet'}); // replace the type by whatever type is your response

    var fileURL = URL.createObjectURL(myBlob);
    // Cross your fingers at this point and pray whatever you're used to pray
    window.open(fileURL);
}

Auf der Komponente rufen Sie den Dienst auf, ohne eine Antwort zu abonnieren. Die vollständige Liste der openOffice-MIME-Typen finden Sie unter: http://www.openoffice.org/framework/documentation/mimetypes/mimetypes.html

5
Ismail H

Für diejenigen, die Redux Pattern verwenden

Ich habe im Datei-Saver als @Hector Cuevas in seiner Antwort hinzugefügt. Mit Angular2 v. 2.3.1 musste ich nicht @ type/file-saver hinzufügen.

Im folgenden Beispiel wird ein Journal als PDF heruntergeladen.

Die Journalaktionen

public static DOWNLOAD_JOURNALS = '[Journals] Download as PDF';
public downloadJournals(referenceId: string): Action {
 return {
   type: JournalActions.DOWNLOAD_JOURNALS,
   payload: { referenceId: referenceId }
 };
}

public static DOWNLOAD_JOURNALS_SUCCESS = '[Journals] Download as PDF Success';
public downloadJournalsSuccess(blob: Blob): Action {
 return {
   type: JournalActions.DOWNLOAD_JOURNALS_SUCCESS,
   payload: { blob: blob }
 };
}

Die Journaleffekte

@Effect() download$ = this.actions$
    .ofType(JournalActions.DOWNLOAD_JOURNALS)
    .switchMap(({payload}) =>
        this._journalApiService.downloadJournal(payload.referenceId)
        .map((blob) => this._actions.downloadJournalsSuccess(blob))
        .catch((err) => handleError(err, this._actions.downloadJournalsFail(err)))
    );

@Effect() downloadJournalSuccess$ = this.actions$
    .ofType(JournalActions.DOWNLOAD_JOURNALS_SUCCESS)
    .map(({payload}) => saveBlobAs(payload.blob, 'journal.pdf'))

Der Journalservice

public downloadJournal(referenceId: string): Observable<any> {
    const url = `${this._config.momentumApi}/api/journals/${referenceId}/download`;
    return this._http.getBlob(url);
}

Der HTTP-Dienst

public getBlob = (url: string): Observable<any> => {
    return this.request({
        method: RequestMethod.Get,
        url: url,
        responseType: ResponseContentType.Blob
    });
};

The journal reducer Obwohl dies nur die korrekten Zustände in unserer Anwendung festlegt, wollte ich es trotzdem hinzufügen, um das vollständige Muster anzuzeigen.

case JournalActions.DOWNLOAD_JOURNALS: {
  return Object.assign({}, state, <IJournalState>{ downloading: true, hasValidationErrors: false, errors: [] });
}

case JournalActions.DOWNLOAD_JOURNALS_SUCCESS: {
  return Object.assign({}, state, <IJournalState>{ downloading: false, hasValidationErrors: false, errors: [] });
}

Ich hoffe das ist hilfreich.

5
Casper Nybroe

Zum Herunterladen und Anzeigen vonPDF-Dateien sehen Sie ein sehr ähnliches Codeausschnitt wie folgt:

  private downloadFile(data: Response): void {
    let blob = new Blob([data.blob()], { type: "application/pdf" });
    let url = window.URL.createObjectURL(blob);
    window.open(url);
  }

  public showFile(fileEndpointPath: string): void {
    let reqOpt: RequestOptions = this.getAcmOptions();  //  getAcmOptions is our helper method. Change this line according to request headers you need.
    reqOpt.responseType = ResponseContentType.Blob;
    this.http
      .get(fileEndpointPath, reqOpt)
      .subscribe(
        data => this.downloadFile(data),
        error => alert("Error downloading file!"),
        () => console.log("OK!")
      );
  }
4
Baatar

Ich verwende Angular 4 mit dem 4,3-httpClient-Objekt. Ich habe eine Antwort modifiziert, die ich in Js 'Technical Blog gefunden habe. Dort wird ein Link-Objekt erstellt, zum Herunterladen verwendet und anschließend zerstört.

Klient:

doDownload(id: number, contentType: string) {
    return this.http
        .get(this.downloadUrl + id.toString(), { headers: new HttpHeaders().append('Content-Type', contentType), responseType: 'blob', observe: 'body' })
}

downloadFile(id: number, contentType: string, filename:string)  {

    return this.doDownload(id, contentType).subscribe(  
        res => { 
            var url = window.URL.createObjectURL(res);
            var a = document.createElement('a');
            document.body.appendChild(a);
            a.setAttribute('style', 'display: none');
            a.href = url;
            a.download = filename;
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove(); // remove the element
        }, error => {
            console.log('download error:', JSON.stringify(error));
        }, () => {
            console.log('Completed file download.')
        }); 

} 

Der Wert von this.downloadUrl wurde zuvor so festgelegt, dass er auf die API verweist. Ich verwende dies zum Herunterladen von Anhängen, daher kenne ich die ID, den Inhaltstyp und den Dateinamen: Ich verwende eine MVC-API, um die Datei zurückzugeben:

 [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
    public FileContentResult GetAttachment(Int32 attachmentID)
    { 
        Attachment AT = filerep.GetAttachment(attachmentID);            
        if (AT != null)
        {
            return new FileContentResult(AT.FileBytes, AT.ContentType);  
        }
        else
        { 
            return null;
        } 
    } 

Die Anhangsklasse sieht folgendermaßen aus:

 public class Attachment
{  
    public Int32 AttachmentID { get; set; }
    public string FileName { get; set; }
    public byte[] FileBytes { get; set; }
    public string ContentType { get; set; } 
}

Das Filerep-Repository gibt die Datei aus der Datenbank zurück.

Hoffe das hilft jemandem :)

4
davaus

Aktualisieren Sie die Antwort von Hector mithilfe von File Saver und HttpClient für Schritt 2:

public downloadFile(file: File): Observable<Blob> {
    return this.http.get(file.fullPath, {responseType: 'blob'})
}
3
dmcgrandle

Hier ist etwas, was ich in meinem Fall getan habe -

// service method
downloadFiles(vendorName, fileName) {
    return this.http.get(this.appconstants.filesDownloadUrl, { params: { vendorName: vendorName, fileName: fileName }, responseType: 'arraybuffer' }).map((res: ArrayBuffer) => { return res; })
        .catch((error: any) => _throw('Server error: ' + error));
}

// a controller function which actually downloads the file
saveData(data, fileName) {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    let blob = new Blob([data], { type: "octet/stream" }),
        url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(url);
}

// a controller function to be called on requesting a download
downloadFiles() {
    this.service.downloadFiles(this.vendorName, this.fileName).subscribe(data => this.saveData(data, this.fileName), error => console.log("Error downloading the file."),
        () => console.info("OK"));
}

Die Lösung wird aus - here

3
Tushar Walzade

Ich habe eine Lösung zum Herunterladen von eckig 2 erhalten, ohne dabei korrupt zu werden

1. Mein Rückgabetyp ist: - ResponseEntity vom Java-Ende. Hier sende ich Byte [] - Array hat den Rückgabetyp vom Controller.

2. Um den Dateisaver in Ihren Arbeitsbereich aufzunehmen - auf der Indexseite:

<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js"></script>

3rd- Bei Komponente ts schreiben Sie diesen Code:

import {ResponseContentType} from '@angular.core';

let headers = new Headers({ 'Content-Type': 'application/json', 'MyApp-Application' : 'AppName', 'Accept': 'application/pdf' });
        let options = new RequestOptions({ headers: headers, responseType: ResponseContentType.Blob });
            this.http
            .post('/project/test/export',
                    somevalue,options)
              .subscribe(data => {

                  var mediaType = 'application/vnd.ms-Excel';
                  let blob: Blob = data.blob();
                    window['saveAs'](blob, 'sample.xls');

                });

Dadurch erhalten Sie das XLS-Dateiformat. Wenn Sie andere Formate wünschen, ändern Sie den Mediatyp und den Dateinamen mit der rechten Erweiterung.

2
user2025069

Es ist besser, wenn Sie versuchen, die neue Methode in Ihnen aufzurufen. subscribe 

this._reportService.getReport()
    .subscribe((data: any) => {
        this.downloadFile(data);
    },
        (error: any) => onsole.log(error),
        () => console.log('Complete')
    );

In downloadFile(data) function müssen wir block, link, href and file name machen

downloadFile(data: any, type: number, name: string) {
    const blob = new Blob([data], {type: 'text/csv'});
    const dataURL = window.URL.createObjectURL(blob);

    // IE doesn't allow using a blob object directly as link href
    // instead it is necessary to use msSaveOrOpenBlob
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
      window.navigator.msSaveOrOpenBlob(blob);
      return;
    }

    const link = document.createElement('a');
    link.href = dataURL;
    link.download = 'export file.csv';
    link.click();

    setTimeout(() => {

      // For Firefox it is necessary to delay revoking the ObjectURL
      window.URL.revokeObjectURL(dataURL);
      }, 100);
    }
}
1
Volodymyr Khmil

Sie können auch eine Datei direkt von Ihrer Vorlage herunterladen, in der Sie das Download-Attribut verwenden, und für [attr.href] einen Eigenschaftswert aus der Komponente bereitstellen. Diese einfache Lösung sollte in den meisten Browsern funktionieren.

<a download [attr.href]="yourDownloadLink"></a>

Verweis: https://www.w3schools.com/tags/att_a_download.asp

0
Max

<a href="my_url" download="myfilename">Download file</a>

my_url sollte denselben Ursprung haben, andernfalls wird es an diesen Ort umgeleitet

0
VIVEK SINGH

Setzen Sie einfach die url als href wie folgt. 

<a href="my_url">Download File</a>
0
Harunur Rashid

Ich war heute mit demselben Fall konfrontiert und musste eine PDF-Datei als Anhang herunterladen (die Datei sollte nicht im Browser gerendert, sondern stattdessen heruntergeladen werden). Um dies zu erreichen, musste ich die Datei in einer Angular Blob abrufen und gleichzeitig einen Content-Disposition-Header in die Antwort einfügen.

Dies war das einfachste, was ich bekommen konnte (Winkel 7):

Im Service:

getFile(id: String): Observable<HttpResponse<Blob>> {
  return this.http.get(`./file/${id}`, {responseType: 'blob', observe: 'response'});
}

Wenn ich dann die Datei in einer Komponente herunterladen muss, kann ich einfach:

fileService.getFile('123').subscribe((file: HttpResponse<Blob>) => window.location.href = file.url);

AKTUALISIEREN:

Überflüssige Header-Einstellung aus dem Dienst entfernt

0
 let headers = new Headers({
                'Content-Type': 'application/json',
                'MyApp-Application': 'AppName',
                'Accept': 'application/vnd.ms-Excel'
            });
            let options = new RequestOptions({
                headers: headers,
                responseType: ResponseContentType.Blob
            });


this.http.post(this.urlName + '/services/exportNewUpc', localStorageValue, options)
                .subscribe(data => {
                    if (navigator.appVersion.toString().indexOf('.NET') > 0)
                    window.navigator.msSaveBlob(data.blob(), "Export_NewUPC-Items_" + this.selectedcategory + "_" + this.retailname +"_Report_"+this.myDate+".xlsx");

                    else {
                        var a = document.createElement("a");
                        a.href = URL.createObjectURL(data.blob());
                        a.download = "Export_NewUPC-Items_" + this.selectedcategory + "_" + this.retailname +"_Report_"+this.myDate+ ".xlsx";
                        a.click();
                    }
                    this.ui_loader = false;
                    this.selectedexport = 0;
                }, error => {
                    console.log(error.json());
                    this.ui_loader = false;
                    document.getElementById("exceptionerror").click();
                });
0
user2025069