page change pdf angular

change - Angular 2 descarga PDF desde la API y lo muestra en vista



router events subscribe angular 4 (7)

Estoy aprendiendo Angular 2 Beta. Me pregunto cómo descargar el archivo PDF desde la API y mostrarlo en mi vista. He intentado hacer una solicitud utilizando lo siguiente:

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

  • Tenga en cuenta que solo uso console.log para ver el valor de r

Pero siempre recibo el siguiente mensaje de excepción:

El método "arrayBuffer ()" no se implementó en la superclase de respuesta

¿Es porque ese método aún no está listo en Angular 2 Beta? ¿O hay algún error que haya cometido?

Cualquier ayuda sería apreciada. Muchas gracias.


Aquí está el código que funciona para descargar la respuesta de la API en IE y chrome / safari. Aquí la variable de respuesta es la respuesta API.

Nota: la llamada http del cliente debe admitir la respuesta de 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); }


Así que aquí es cómo me las arreglé para hacerlo funcionar. Mi situación: necesitaba descargar un PDF desde mi punto final de API y guardar el resultado como un PDF en el navegador.

Para admitir el guardado de archivos en todos los navegadores, usé el módulo FileSaver.js .

Creé un componente que toma la ID del archivo para descargar como parámetro. El componente, , se llama así:

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

El componente en sí utiliza XHR para recuperar / guardar el archivo con el número indicado en el parámetro no . De esta manera podemos evitar el hecho de que el módulo http de Angular2 aún no admite tipos de resultados binarios.

Y ahora, sin más dilación, el código componente:

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

He usado Font Awesome para las fuentes usadas en la plantilla. Quería que el componente mostrara un botón de descarga y un girador mientras se busca el pdf.

Además, tenga en cuenta que podría usar require para recuperar el módulo fileSaver.js. Esto se debe a que estoy usando WebPack, por lo que puedo requerir / importar como quiera. Su sintaxis puede ser diferente dependiendo de su herramienta de construcción.


De hecho, esta característica aún no está implementada en el soporte HTTP.

Como solución alternativa, debe ampliar la clase de Angular2 de BrowserXhr como se describe a continuación para establecer responseType en blob en el objeto xhr subyacente:

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

Luego, debe ajustar la carga útil de respuesta en un objeto Blob y usar la biblioteca FileSaver para abrir el cuadro de diálogo de descarga:

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

La biblioteca de FileSaver debe incluirse en su archivo HTML:

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

Ver este plunkr: http://plnkr.co/edit/tfpS9k2YOO1bMgXBky5Y?p=preview

Desafortunadamente, esto establecerá el tipo de responseType para todas las solicitudes AJAX. Para poder establecer el valor de esta propiedad, hay más actualizaciones que hacer en las clases XHRConnection y Http .

Como referencias ver estos enlaces:

Editar

Después de pensar un poco más, creo que podría aprovechar los inyectores jerárquicos y configurar este proveedor solo al nivel del componente que ejecuta la descarga:

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

Esta anulación solo se aplicaría a este componente (no olvide eliminar la provisión correspondiente al iniciar su aplicación). El componente de descarga podría ser usado así:

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


Esta es la forma más sencilla de descargar un archivo desde una API que pude encontrar.

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

Llame al método downloadFile(api,fileName) desde su clase de componente.

Para obtener FileSaver ejecute los siguientes comandos en su terminal

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


No creo que todos estos hacks sean necesarios. Acabo de hacer una prueba rápida con el servicio http estándar en angular 2.0 y funcionó como se esperaba.

/* 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 */ } ); }


Para que Filesaver funcione en Angular 5: Instalar

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

En su componente use import * as FileSaver from "file-saver";

y use FileSaver. por defecto y no FileSaver. Guardar como

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


Hola , aquí hay un ejemplo de trabajo . También es adecuado para PDF! application / octet-stream - tipo general. Controlador:

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:

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

Instale los paquetes de npm para el protector de archivos "file-saver": "^ 1.3.3", "@ types / file-saver": "0.0.0" e incluya en vendor.ts import ''file-saver'';

Descarga de componentes 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); } ); } }

Utilizando

<download-btn api="api/realisations/realisationsExcel"></download-btn>