Comment afficher le blob (.pdf) dans une application AngularJS


106

J'ai essayé d'afficher le fichier pdf que j'obtiens comme un blob d'une $http.postréponse. Le pdf doit être affiché dans l'application en utilisant <embed src>par exemple.

Je suis tombé sur quelques articles de pile, mais mon exemple ne semble pas fonctionner.

JS:

D'après ce doc , j'ai continué et j'ai essayé ...

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

Maintenant, d'après ce que je comprends, fileURLcrée une URL temporaire que le blog peut utiliser comme référence.

HTML:

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

Je ne sais pas comment gérer cela dans Angular, la situation idéale serait de (1) l' attribuer à une portée, (2) `` préparer / reconstruire '' le blob en pdf (3) le transmettre au HTML en utilisant <embed>parce que je souhaitez l'afficher dans l'application.

Je fais des recherches depuis plus d'un jour maintenant, mais je n'arrive pas à comprendre comment cela fonctionne dans Angular ... Et supposons simplement que les bibliothèques de visionneuse PDF n'étaient pas une option.


Salut D'lo DeProjuicer, avez-vous réussi à résoudre votre problème de génération du PDF via angular?
Raymond Nakampe le

@michael D'lo DeProjuicer Que faire pour le même cas en angulaire 2?
monica

Réponses:


214

Tout d'abord, vous devez définir le responseTypesur arraybuffer. Cela est nécessaire si vous souhaitez créer un objet blob de vos données. Voir Sending_and_Receiving_Binary_Data . Donc, votre code ressemblera à ceci:

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

La partie suivante est que vous devez utiliser le service $ sce pour rendre votre URL de confiance angulaire. Cela peut être fait de cette manière:

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

N'oubliez pas d'injecter le service $ sce .

Si tout cela est fait, vous pouvez maintenant intégrer votre pdf:

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

9
Pour moi, cela ne fonctionnait pas dans Chrome (35.0.1916.114 m). Résolu ce problème en utilisant <object> au lieu de <embed>: <object data = "{{content}}" type = "application / pdf"> </object>
HoffZ

2
Pour moi (AngularJS 1.25) je devais faire: new Blob ([response.data]
Martin Connell

2
@HoffZ: J'ai remplacé la méthode de raccourci $http.getpar une méthode complète, en spécifiant le responseTypechamp: { 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' }Et ça marche :)
Nikolay Melnikov

1
Pour moi, le seul moyen de le faire fonctionner était de créer le blob avec response.dataau lieu de response, comme ceci:var file = new Blob([response.data], {type: 'application/pdf'});
Alekos Filini

1
@ yosep-kim cela ne fonctionne pas sur IE car l'objet URL n'existe pas dans IE: caniuse.com/#search=URL
Carlos

32

J'utilise AngularJS v1.3.4

HTML:

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

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

Services JS:

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

Services Web Java REST - 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;
    }

quelle version de safari? window.URL est bon en safari 9 et après: caniuse.com/#search=createObjectURL
Stéphane GRILLON

J'ai testé et validé sur mon MacBook pro et safari 9.0.2.
Stéphane GRILLON

Idem, macBook el capitaine. window.URL.createObjectURL (fichier); je ne sais pas où est le problème mais le code ne fonctionne pas. Peut-être que je fais quelque chose de mal. Tout merci. Je n'ai pas le temps de vérifier ce qui ne fonctionne pas et d'utiliser FileSaver.js
fdrv

si votre candidature est en ligne, postez votre URL s'il vous plaît? avez-vous le même Back-End?
Stéphane GRILLON

l'attribut de téléchargement n'est pas pris en charge dans safari. caniuse.com/#search=download
Biswanath

21

Les suggestions de michael fonctionnent comme un charme pour moi :) Si vous remplacez $ http.post par $ http.get, rappelez-vous que la méthode .get accepte 2 paramètres au lieu de 3 ... c'est là que j'ai perdu mon temps ...;)

manette:

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

vue:

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

responseType:'arraybuffer', vient de me sauver quelques heures de sommeil! +1
svarog

comment déclencher la sauvegarde à la place pour l'imprimer en html?
fdrv

merci, cela m'a sauvé quelques heures, vous pouvez également remplacer $scope.content = $sce.trustAsResourceUrl(fileURL);avec $window.open(fileURL, '_self', '');et ouvrir le fichier sur plein écran.
Tavitos

9

J'ai rencontré des difficultés à utiliser "window.URL" avec Opera Browser car il en résulterait "undefined". De plus, avec window.URL, le document PDF ne s'est jamais ouvert dans Internet Explorer et Microsoft Edge (il resterait en attente pour toujours). J'ai proposé la solution suivante qui fonctionne dans IE, Edge, Firefox, Chrome et Opera (je n'ai pas testé avec 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);
    }
}

Faites-moi savoir si cela a aidé! :)


Cette approche n'ouvre pas le document PDF dans la fenêtre du navigateur dans IE mais invite l'utilisateur à le télécharger. Y a-t-il un travail autour de cela?
sdd

1
Le code ci-dessus consiste à télécharger le fichier PDF et à laisser votre application PDF Reader par défaut prendre le relais pour l'ouvrir. Cela fonctionne même bien sur les appareils mobiles. La raison est que, même si j'ai pu ouvrir le PDF sur certains navigateurs, je ne pouvais pas l'ouvrir sur d'autres. J'ai donc pensé qu'il était préférable d'avoir une solution qui fonctionnerait sur tous les navigateurs (y compris les navigateurs mobiles) pour télécharger le fichier PDF.
Manuel Hernandez

Vous pouvez utiliser le code suivant pour afficher le PDF dans un nouvel onglet: window.open (reader.result, '_blank');
samneric

6

L'ajout de responseType à la requête faite à partir d'angular est en effet la solution, mais pour moi, cela n'a pas fonctionné tant que j'ai défini responseType sur blob , pas sur arrayBuffer. Le code est explicite:

    $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
en fait, avec le 'blob'type, il est possible d'écrire plus court: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response));Pas besoin de créerBlob
Alena Kastsiukavets

0

J'ai eu du mal ces derniers jours à essayer de télécharger des fichiers PDF et des images, tout ce que j'ai pu télécharger était de simples fichiers texte.

La plupart des questions ont les mêmes éléments, mais il a fallu un certain temps pour trouver le bon ordre pour que cela fonctionne.

Merci @Nikolay Melnikov, votre commentaire / réponse à cette question est ce qui l'a fait fonctionner.

En un mot, voici mon appel au backend du service 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'
    });
  }

Depuis mon contrôleur:

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

Réponse la plus récente (pour 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

Une suggestion de code que je viens d'utiliser dans mon projet en utilisant 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
s'il vous plaît ajouter un bref aussi.
Farhana
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.