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でそのメソッドがまだ準備されていないからでしょうか?または、私が犯した間違いはありますか?
任意の助けをいただければ幸いです。どうもありがとうございました。
実際、この機能はまだHTTPサポートに実装されていません。
回避策として、下に説明するようにAngular2のBrowserXhr
クラスを拡張して、基になるxhrオブジェクトでresponseType
をblob
に設定する必要があります。
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 ]
})
だからここに私がそれを機能させる方法を示します。私の状況: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を使用しているため、希望どおりに要求/インポートできるためです。ビルドツールによって構文が異なる場合があります。
これらのハッキングのすべてが必要だとは思いません。 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 */ }
);
}
これが、私が思いついた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
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>
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);
以下は、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);
}
http
.post(url, data, {
responseType: "blob",
observe: "response"
})
.pipe(
map(response => {
saveAs(response.body, "fileName.pdf");
})
);
バイト配列として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 を参照してください。