web-dev-qa-db-ja.com

Angular 2 APIからPDFをダウンロードし、ビューに表示します

Angular 2 Betaを学んでいます。 APIからPDFファイルをダウンロードして、ビューに表示する方法を知りたいですか?私は次を使用してリクエストを作成しようとしました:

    var headers = new Headers();
    headers.append('Accept', 'application/pdf');
    var options = new ResponseOptions({
        headers: headers
    });
    var response = new Response(options);
    this.http.get(this.setUrl(endpoint), response).map(res => res.arrayBuffer()).subscribe(r=>{
       console.log(r);
    })
  • console.logのみを使用してrの値を表示することに注意してください

ただし、次の例外メッセージが常に表示されます。

「arrayBuffer()」メソッドはResponseスーパークラスに実装されていません

Angular 2 Betaでそのメソッドがまだ準備されていないからでしょうか?または、私が犯した間違いはありますか?

任意の助けをいただければ幸いです。どうもありがとうございました。

26
asubanovsky

実際、この機能はまだHTTPサポートに実装されていません。

回避策として、下に説明するようにAngular2のBrowserXhrクラスを拡張して、基になるxhrオブジェクトでresponseTypeblobに設定する必要があります。

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";
    return <any>(xhr);
  }
}

次に、応答ペイロードをBlobオブジェクトにラップし、FileSaverライブラリを使用してダウンロードダイアログを開く必要があります。

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

FileSaverライブラリをHTMLファイルに含める必要があります。

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

このplunkrを参照してください: http://plnkr.co/edit/tfpS9k2YOO1bMgXBky5Y?p=preview

残念ながら、これはすべてのAJAXリクエストに対してresponseTypeを設定します。このプロパティの値を設定できるようにするには、XHRConnectionクラスとHttpクラスでさらに更新する必要があります。

参照としてこれらのリンクを参照してください:

編集

もう少し考えた後、階層インジェクターを活用して、ダウンロードを実行するコンポーネントのレベルでのみこのプロバイダーを構成できると思います。

@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);
        });
    }
}

このオーバーライドは、このコンポーネントにのみ適用されます(アプリケーションをブートストラップするときに、対応する提供を削除することを忘れないでください)。ダウンロードコンポーネントは次のように使用できます。

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

だからここに私がそれを機能させる方法を示します。私の状況:APIエンドポイントからPDFをダウンロードし、結果をブラウザーにPDFとして保存する必要がありました。

すべてのブラウザーでファイル保存をサポートするために、 FileSaver.js モジュールを使用しました。

パラメーターとしてダウンロードするファイルのIDを取得するコンポーネントを作成しました。コンポーネント、は次のように呼び出されます。

<pdf-downloader no="24234232"></pdf-downloader>

コンポーネント自体は、XHRを使用して、noパラメーターで指定された番号のファイルをフェッチ/保存します。これにより、Angular2 httpモジュールがバイナリ結果タイプをまだサポートしていないという事実を回避できます。

そして今、さらに苦労せずに、コンポーネントコード:

    import {Component,Input } from 'angular2/core';
    import {BrowserXhr} from 'angular2/http';

    // Use Filesaver.js to save binary to file
    // https://github.com/eligrey/FileSaver.js/
    let fileSaver = require('filesaver.js');


    @Component({
      selector: 'pdf-downloader',
      template: `
        <button
           class="btn btn-secondary-outline btn-sm "
          (click)="download()">
            <span class="fa fa-download" *ngIf="!pending"></span>
            <span class="fa fa-refresh fa-spin" *ngIf="pending"></span>
        </button>
        `
   })

   export class PdfDownloader  {

       @Input() no: any;

       public pending:boolean = false;

       constructor() {}

       public download() {

        // Xhr creates new context so we need to create reference to this
        let self = this;

        // Status flag used in the template.
        this.pending = true;

        // Create the Xhr request object
        let xhr = new XMLHttpRequest();
        let url =  `/api/pdf/iticket/${this.no}?lang=en`;
        xhr.open('GET', url, true);
        xhr.responseType = 'blob';

        // Xhr callback when we get a result back
        // We are not using arrow function because we need the 'this' context
        xhr.onreadystatechange = function() {

            // We use setTimeout to trigger change detection in Zones
            setTimeout( () => { self.pending = false; }, 0);

            // If we get an HTTP status OK (200), save the file using fileSaver
            if(xhr.readyState === 4 && xhr.status === 200) {
                var blob = new Blob([this.response], {type: 'application/pdf'});
                fileSaver.saveAs(blob, 'Report.pdf');
            }
        };

        // Start the Ajax request
        xhr.send();
    }
}

テンプレートで使用されるフォントに Font Awesome を使用しました。 PDFの取得中に、コンポーネントにダウンロードボタンとスピナーを表示したかったのです。

また、requireを使用してfileSaver.jsモジュールを取得できることに注意してください。これは、WebPackを使用しているため、希望どおりに要求/インポートできるためです。ビルドツールによって構文が異なる場合があります。

17
Spock

これらのハッキングのすべてが必要だとは思いません。 angular 2.0の標準httpサービスで簡単なテストを行ったところ、期待どおりに機能しました。

/* generic download mechanism */
public download(url: string, data: Object = null): Observable<Response> {

    //if custom headers are required, add them here
    let headers = new Headers();        

    //add search parameters, if any
    let params = new URLSearchParams();
    if (data) {
        for (let key in data) {
            params.set(key, data[key]);
        }
    }

    //create an instance of requestOptions 
    let requestOptions = new RequestOptions({
        headers: headers,
        search: params
    });

    //any other requestOptions
    requestOptions.method = RequestMethod.Get;
    requestOptions.url = url;
    requestOptions.responseType = ResponseContentType.Blob;

    //create a generic request object with the above requestOptions
    let request = new Request(requestOptions);

    //get the file
    return this.http.request(request)
        .catch(err => {
            /* handle errors */
        });      
}


/* downloads a csv report file generated on the server based on search criteria specified. Save using fileSaver.js. */
downloadSomethingSpecifc(searchCriteria: SearchCriteria): void {

    download(this.url, searchCriteria) 
        .subscribe(
            response => {                                
                let file = response.blob();
                console.log(file.size + " bytes file downloaded. File type: ", file.type);                
                saveAs(file, 'myCSV_Report.csv');
            },
            error => { /* handle errors */ }
        );
}
7
Indev

これが、私が思いついたAPIからファイルをダウンロードする最も簡単な方法です。

import { Injectable } from '@angular/core';
import { Http, ResponseContentType } from "@angular/http";

import * as FileSaver from 'file-saver';

@Injectable()
export class FileDownloadService {


    constructor(private http: Http) { }

    downloadFile(api: string, fileName: string) {
        this.http.get(api, { responseType: 'blob' })
            .subscribe((file: Blob) => {
               FileSaver.saveAs(file, fileName);
        });    
    }

}

コンポーネントクラスからdownloadFile(api,fileName)メソッドを呼び出します。

FileSaverを取得するには、ターミナルで次のコマンドを実行します

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

Hello、これはworkingの例です。 PDFにも適しています! application/octet-stream-一般的なタイプ。コントローラ:

public FileResult exportExcelTest()
{ 
    var contentType = "application/octet-stream";
    HttpContext.Response.ContentType = contentType;

    RealisationsReportExcell reportExcell = new RealisationsReportExcell();     
    byte[] filedata = reportExcell.RunSample1();

    FileContentResult result = new FileContentResult(filedata, contentType)
    {
        FileDownloadName = "report.xlsx"
    };
    return result;
}

Angular2:

サービスxhr:

import { Injectable } from '@angular/core';
import { BrowserXhr } from '@angular/http';

@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
  constructor() {
      super();
  }

  public build(): any {
      let xhr = super.build();
      xhr.responseType = "blob";
      return <any>(xhr);
  }   
}

ファイルセーバーnpmパッケージ "file-saver": "^ 1.3.3"、 "@ types/file-saver": "0.0.0"をインストールし、vendor.ts import 'file-saver'に含めます。

コンポーネントbtnダウンロード。

import { Component, OnInit, Input } from "@angular/core";
import { Http, ResponseContentType } from '@angular/http';
import { CustomBrowserXhr } from '../services/customBrowserXhr.service';
import * as FileSaver from 'file-saver';

@Component({
    selector: 'download-btn',
    template: '<button type="button" (click)="downloadFile()">Download</button>',
    providers: [
        { provide: CustomBrowserXhr, useClass: CustomBrowserXhr }
    ]
})

export class DownloadComponent {        
    @Input() api: string; 

    constructor(private http: Http) {
    }

    public downloadFile() {
        return this.http.get(this.api, { responseType: ResponseContentType.Blob })
        .subscribe(
            (res: any) =>
            {
                let blob = res.blob();
                let filename = 'report.xlsx';
                FileSaver.saveAs(blob, filename);
            }
        );
    }
}

を使用して

<download-btn api="api/realisations/realisationsExcel"></download-btn>
4
dev-siberia

FilesaverをAngular 5で動作させるには:インストール

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

コンポーネントでimport * as FileSaver from "file-saver";を使用します

fileSaverを使用します。デフォルト FileSaverではありません。SaveAs

.subscribe(data => {
            const blob = data.data;
            const filename = "filename.txt";
            FileSaver.default(blob, filename);
2

以下は、IEおよびchrome/safariでAPI responeをダウンロードするために機能するコードです。ここで、応答変数はAPI応答です。

注:クライアントからのhttp呼び出しは、blob応答をサポートする必要があります。

    let blob = new Blob([response], {type: 'application/pdf'});
    let fileUrl = window.URL.createObjectURL(blob);
    if (window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveOrOpenBlob(blob, fileUrl.split(':')[1] + '.pdf');
    } else {
        window.open(fileUrl);
    }
1
Dilip Nannaware
http
  .post(url, data, {
    responseType: "blob",
    observe: "response"
  })
  .pipe(
    map(response => {
      saveAs(response.body, "fileName.pdf");
    })
  );
0
Eylon Sultan

バイト配列としてPDFをロードするC#Web APIを使用した作業ソリューション:

C#はPDFをバイト配列としてロードし、Base64エンコード文字列に変換します

public HttpResponseMessage GetPdf(Guid id)
{
    byte[] file = GetFile(id);
    HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
    result.Content = new StringContent("data:application/pdf;base64," + Convert.ToBase64String(file));
    return result;
}

AngularサービスはPDFを取得します

getPdf(): Observable<string> {
    return this.http.get(webApiRequest).pipe(
        map(response => {
            var anonymous = <any>response;
            return anonymous._body;
        })
    );
}

コンポーネントビューは、サービスレスポンスへのバインドを介してPDFを埋め込みます

以下のpdfSource変数は、サービスから返された値です。

<embed [src]="sanitizer.bypassSecurityTrustResourceUrl(pdfSource)" type="application/pdf" width="100%" height="300px" />

詳細については、Angular DomSanitizer docs を参照してください。

0