Como exibir blob (.pdf) em um aplicativo AngularJS


106

Tenho tentado exibir o arquivo PDF que estou obtendo como um blob de uma $http.postresposta. O pdf deve ser exibido dentro do aplicativo usando<embed src> por exemplo.

Eu me deparei com alguns posts, mas de alguma forma meu exemplo não parece funcionar.

JS:

De acordo com este doc , continuei e tentei ...

$http.post('/postUrlHere',{myParams}).success(function (response) {
 var file = new Blob([response], {type: 'application/pdf'});
 var fileURL = URL.createObjectURL(file);
 $scope.content = fileURL;
});

Agora, pelo que entendi, fileURL cria um URL temporário que o blog pode usar como referência.

HTML:

<embed src="{{content}}" width="200" height="200"></embed>

Não tenho certeza de como lidar com isso no Angular, a situação ideal seria (1) atribuí-lo a um escopo, (2) 'preparar / reconstruir' o blob para um pdf (3) passá-lo para o HTML usando<embed> porque eu deseja exibi-lo no aplicativo.

Venho pesquisando há mais de um dia, mas de alguma forma não consigo entender como isso funciona no Angular ... E vamos apenas assumir que as bibliotecas do visualizador de PDF por aí não eram uma opção.


Olá D'lo DeProjuicer, você conseguiu consertar seu problema de geração de PDF via angular?
— Raymond Nakampe

@michael D'lo DeProjuicer O que deve ser feito para o mesmo gabinete no angular 2?
— monica

Respostas:


214

Primeiro de tudo, você precisa definir o responseTypeparaarraybuffer . Isso é necessário se você deseja criar um blob de seus dados. Consulte Sending_and_Receiving_Binary_Data . Portanto, seu código será semelhante a este:

$http.post('/postUrlHere',{myParams}, {responseType:'arraybuffer'})
  .success(function (response) {
       var file = new Blob([response], {type: 'application/pdf'});
       var fileURL = URL.createObjectURL(file);
});

A próxima parte é, você precisa usar o serviço $ sce para tornar o angular trust seu url. Isso pode ser feito desta forma:

$scope.content = $sce.trustAsResourceUrl(fileURL);

Não se esqueça de injetar o serviço $ sce .

Se tudo isso estiver feito, agora você pode incorporar seu pdf:

<embed ng-src="{{content}}" style="width:200px;height:200px;"></embed>

9
Para mim, isso não funcionou no Chrome (35.0.1916.114 m). Resolvido isso usando <object> em vez de <embed>: <object data = "{{content}}" type = "application / pdf"> </object>
— HoffZ

2
Para mim (AngularJS 1.25) eu tinha que fazer: novo Blob ([response.data]
— Martin Connell

2
@HoffZ: Substituí o método de atalho $http.getpor um completo, especificando o responseTypecampo: { url: "http://127.0.0.1:8080/resources/jobs/af471106-2e71-4fe6-946c-cd1809c659e5/result/?key="+$scope.key, method: "GET", headers: { 'Accept': 'application/pdf' }, responseType: 'arraybuffer' }E funciona :)
— Nikolay Melnikov

1
Para mim, a única maneira de fazer funcionar era criar o blob com, em response.datavez de response, assim:var file = new Blob([response.data], {type: 'application/pdf'});
— Alekos Filini

1
@ yosep-kim isto não funciona no IE porque o objeto URL não existe no IE: caniuse.com/#search=URL
— Carlos

32

Eu uso AngularJS v1.3.4

HTML:

<button ng-click="downloadPdf()" class="btn btn-primary">download PDF</button>

Controlador JS:

'use strict';
angular.module('xxxxxxxxApp')
    .controller('xxxxController', function ($scope, xxxxServicePDF) {
        $scope.downloadPdf = function () {
            var fileName = "test.pdf";
            var a = document.createElement("a");
            document.body.appendChild(a);
            a.style = "display: none";
            xxxxServicePDF.downloadPdf().then(function (result) {
                var file = new Blob([result.data], {type: 'application/pdf'});
                var fileURL = window.URL.createObjectURL(file);
                a.href = fileURL;
                a.download = fileName;
                a.click();
            });
        };
});

Serviços JS:

angular.module('xxxxxxxxApp')
    .factory('xxxxServicePDF', function ($http) {
        return {
            downloadPdf: function () {
            return $http.get('api/downloadPDF', { responseType: 'arraybuffer' }).then(function (response) {
                return response;
            });
        }
    };
});

Java REST Web Services - Spring MVC:

@RequestMapping(value = "/downloadPDF", method = RequestMethod.GET, produces = "application/pdf")
    public ResponseEntity<byte[]> getPDF() {
        FileInputStream fileStream;
        try {
            fileStream = new FileInputStream(new File("C:\\xxxxx\\xxxxxx\\test.pdf"));
            byte[] contents = IOUtils.toByteArray(fileStream);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/pdf"));
            String filename = "test.pdf";
            headers.setContentDispositionFormData(filename, filename);
            ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(contents, headers, HttpStatus.OK);
            return response;
        } catch (FileNotFoundException e) {
           System.err.println(e);
        } catch (IOException e) {
            System.err.println(e);
        }
        return null;
    }

qual versão do safari? window.URL é bom no safari 9 e depois: caniuse.com/#search=createObjectURL
— Stéphane GRILLON

Testei e validei no meu MacBook pro e safari 9.0.2.
— Stéphane GRILLON

O mesmo, macBook el capitão. window.URL.createObjectURL (arquivo); Eu não onde está o problema, mas o código não funciona. Pode ser que eu faça algo errado. Obrigado. Não tenho tempo para verificar o que não está funcionando e usar FileSaver.js
— fdrv

se seu aplicativo estiver online, poste seu URL, por favor? você tem o mesmo back-end?
— Stéphane GRILLON

O atributo de download não é compatível com o Safari. caniuse.com/#search=download
— Biswanath

21

as sugestões de Michael funcionam perfeitamente para mim :) Se você substituir $ http.post por $ http.get, lembre-se de que o método .get aceita 2 parâmetros em vez de 3 ... é aqui que perco meu tempo ...;)

controlador:

$http.get('/getdoc/' + $stateParams.id,     
{responseType:'arraybuffer'})
  .success(function (response) {
     var file = new Blob([(response)], {type: 'application/pdf'});
     var fileURL = URL.createObjectURL(file);
     $scope.content = $sce.trustAsResourceUrl(fileURL);
});

Visão:

<object ng-show="content" data="{{content}}" type="application/pdf" style="width: 100%; height: 400px;"></object>

responseType:'arraybuffer', só me salvou algumas horas de sono! +1
— svarog

como acionar o save em vez de imprimi-lo em html?
— fdrv

obrigado, isso me salvou um par de horas, você também pode substituir $scope.content = $sce.trustAsResourceUrl(fileURL);com $window.open(fileURL, '_self', '');e abra o arquivo em tela cheia.
— Tavitos

9

Tive dificuldades em usar "window.URL" com o navegador Opera, pois resultaria em "indefinido". Além disso, com window.URL, o documento PDF nunca foi aberto no Internet Explorer e no Microsoft Edge (ele ficaria esperando para sempre). Eu vim com a seguinte solução que funciona no IE, Edge, Firefox, Chrome e Opera (não testei com Safari):

$http.post(postUrl, data, {responseType: 'arraybuffer'})
.success(success).error(failed);

function success(data) {
   openPDF(data.data, "myPDFdoc.pdf");
};

function failed(error) {...};

function openPDF(resData, fileName) {
    var ieEDGE = navigator.userAgent.match(/Edge/g);
    var ie = navigator.userAgent.match(/.NET/g); // IE 11+
    var oldIE = navigator.userAgent.match(/MSIE/g); 

    var blob = new window.Blob([resData], { type: 'application/pdf' });

    if (ie || oldIE || ieEDGE) {
       window.navigator.msSaveBlob(blob, fileName);
    }
    else {
       var reader = new window.FileReader();
       reader.onloadend = function () {
          window.location.href = reader.result;
       };
       reader.readAsDataURL(blob);
    }
}

Deixe-me saber se ajudou! :)


Essa abordagem não abre o documento PDF na janela do navegador no IE, mas solicita que o usuário faça o download. Existe alguma solução para isso?
— sdd

1
O código acima é para baixar o arquivo PDF e permitir que seu aplicativo PDF Reader padrão assuma o controle para abri-lo. Até funciona bem em dispositivos móveis. A razão é que, embora eu conseguisse abrir o PDF em alguns navegadores, não consegui abri-lo em outros. Portanto, achei melhor ter uma solução que rodasse em todos os navegadores (incluindo navegadores móveis) para baixar o arquivo PDF.
— Manuel Hernandez

Você pode usar o seguinte código para visualizar o PDF em uma nova guia: window.open (reader.result, '_blank');
— samneric

6

Adicionar responseType à solicitação feita a partir do angular é de fato a solução, mas para mim não funcionou até que eu defina responseType como blob , não como arrayBuffer. O código é autoexplicativo:

    $http({
            method : 'GET',
            url : 'api/paperAttachments/download/' + id,
            responseType: "blob"
        }).then(function successCallback(response) {
            console.log(response);
             var blob = new Blob([response.data]);
             FileSaver.saveAs(blob, getFileNameFromHttpResponse(response));
        }, function errorCallback(response) {   
        });

2
na verdade, com 'blob'tipo é possível escrever mais curto: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response));Não há necessidade de criarBlob
— Alena Kastsiukavets

0

Eu tenho lutado nos últimos dias tentando fazer download de PDFs e imagens, tudo o que consegui fazer foram arquivos de texto simples.

A maioria das perguntas tem os mesmos componentes, mas demorou um pouco para descobrir a ordem certa para que funcionasse.

Obrigado @Nikolay Melnikov, seu comentário / resposta a esta pergunta foi o que fez funcionar.

Em poucas palavras, aqui está minha chamada de back-end do serviço AngularJS:

  getDownloadUrl(fileID){
    //
    //Get the download url of the file
    let fullPath = this.paths.downloadServerURL + fileId;
    //
    // return the file as arraybuffer 
    return this.$http.get(fullPath, {
      headers: {
        'Authorization': 'Bearer ' + this.sessionService.getToken()
      },
      responseType: 'arraybuffer'
    });
  }

Do meu controlador:

downloadFile(){
   myService.getDownloadUrl(idOfTheFile).then( (response) => {
      //Create a new blob object
      let myBlobObject=new Blob([response.data],{ type:'application/pdf'});

      //Ideally the mime type can change based on the file extension
      //let myBlobObject=new Blob([response.data],{ type: mimeType});

      var url = window.URL || window.webkitURL
      var fileURL = url.createObjectURL(myBlobObject);
      var downloadLink = angular.element('<a></a>');
      downloadLink.attr('href',fileURL);
      downloadLink.attr('download',this.myFilesObj[documentId].name);
      downloadLink.attr('target','_self');
      downloadLink[0].click();//call click function
      url.revokeObjectURL(fileURL);//revoke the object from URL
    });
}

0

Resposta mais recente (para Angular 8+):

this.http.post("your-url",params,{responseType:'arraybuffer' as 'json'}).subscribe(
  (res) => {
    this.showpdf(res);
  }
)};

public Content:SafeResourceUrl;
showpdf(response:ArrayBuffer) {
  var file = new Blob([response], {type: 'application/pdf'});
  var fileURL = URL.createObjectURL(file);
  this.Content = this.sanitizer.bypassSecurityTrustResourceUrl(fileURL);
}

  HTML :

  <embed [src]="Content" style="width:200px;height:200px;" type="application/pdf" />

-1

Uma sugestão de código que acabei de usar em meu projeto usando AngularJS v1.7.2

$http.get('LabelsPDF?ids=' + ids, { responseType: 'arraybuffer' })
            .then(function (response) {
                var file = new Blob([response.data], { type: 'application/pdf' });
                var fileURL = URL.createObjectURL(file);
                $scope.ContentPDF = $sce.trustAsResourceUrl(fileURL);
            });

<embed ng-src="{{ContentPDF}}" type="application/pdf" class="col-xs-12" style="height:100px; text-align:center;" />

1
por favor, adicione alguns resumos também.
— Farhana
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.