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.

Simo D'lo Mafuxwana
la source
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>
Michael
la source
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;
    }
Stéphane GRILLON
la source
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>
Jan Tchärmän
la source
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é! :)

Manuel Hernandez
la source
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) {   
        });
Ancab
la source
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
    });
}
Javier Carbajal
la source
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" />
ashishpm
la source
-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;" />
Fernando Magno
la source
1
s'il vous plaît ajouter un bref aussi.
Farhana