Jak wyświetlić obiekt BLOB (.pdf) w aplikacji AngularJS

106

Próbowałem wyświetlić plik pdf, który otrzymuję jako kroplę z $http.postodpowiedzi. Plik PDF musi być wyświetlany w aplikacji za pomocą <embed src>np.

Natknąłem się na kilka postów na stosie, ale jakoś mój przykład nie działa.

JS:

Według tego doktora kontynuowałem i próbowałem ...

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

Teraz z tego, co rozumiem, fileURLtworzy tymczasowy adres URL, którego blog może używać jako odniesienia.

HTML:

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

Nie jestem pewien, jak sobie z tym poradzić w Angular, idealną sytuacją byłoby (1) przypisanie go do zakresu, (2) „przygotowanie / przebudowanie” obiektu blob do pliku pdf (3) przekazanie go do HTML za pomocą, <embed>ponieważ ja chcesz go wyświetlić w aplikacji.

Badam od ponad dnia, ale jakoś nie mogę zrozumieć, jak to działa w Angular ... I załóżmy, że biblioteki przeglądarek PDF nie były dostępne.

Simo D'lo Mafuxwana
źródło
Cześć D'lo DeProjuicer, czy udało ci się uzyskać problem z generowaniem pliku PDF przez kątową naprawioną?
Raymond Nakampe
@michael D'lo DeProjuicer Co zrobić dla tego samego przypadku w kątowej 2?
monica

Odpowiedzi:

214

Przede wszystkim musisz ustawić responseTypeto arraybuffer. Jest to wymagane, jeśli chcesz utworzyć obiekt blob swoich danych. Zobacz Sending_and_Receiving_Binary_Data . Twój kod będzie więc wyglądał następująco:

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

Następna część polega na tym, że musisz użyć usługi $ sce , aby uzyskać zaufanie kątowe do swojego adresu URL. Można to zrobić w następujący sposób:

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

Nie zapomnij wstrzyknąć usługi $ sce .

Jeśli to wszystko jest zrobione, możesz teraz osadzić swój plik PDF:

<embed ng-src="{{content}}" style="width:200px;height:200px;"></embed>
Michael
źródło
9
U mnie to nie działało w Chrome (35.0.1916.114 m). Rozwiązano to za pomocą <object> zamiast <embed>: <object data = "{{content}}" type = "application / pdf"> </object>
HoffZ,
2
Dla mnie (AngularJS 1.25) musiałem zrobić: nowy Blob ([dane odpowiedzi]
Martin Connell,
2
@HoffZ: Zamieniłem metodę skrótową $http.getna pełną, podając responseTypepole: { 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' }I działa :)
Nikolay Melnikov
1
Dla mnie jedynym sposobem, aby to zadziałało, było utworzenie bloba za pomocą response.datazamiast responsetego:var file = new Blob([response.data], {type: 'application/pdf'});
Alekos Filini
1
@ yosep-kim to nie działa w IE, ponieważ obiekt URL nie istnieje w IE: caniuse.com/#search=URL
Carlos
32

Używam AngularJS v1.3.4

HTML:

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

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

Usługi JS:

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

Usługi sieciowe 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
źródło
która wersja safari? window.URL jest dobry w Safari 9 i później: caniuse.com/#search=createObjectURL
Stéphane GRILLON
Przetestowałem i zweryfikowałem na moim MacBooku Pro i Safari 9.0.2.
Stéphane GRILLON
To samo, kapitanie MacBook el. window.URL.createObjectURL (plik); Nie wiem, gdzie jest problem, ale kod nie działa. Może zrobię coś złego. Dziękuję. Nie mam czasu sprawdzić, co nie działa i użyć FileSaver.js
fdrv
jeśli zgłoszenie jest online, proszę zamieścić swój adres URL? czy masz ten sam Back-End?
Stéphane GRILLON
atrybut pobierania nie jest obsługiwany w Safari. caniuse.com/#search=download
Biswanath
21

sugestie Michaela działają dla mnie jak urok :) Jeśli zamienisz $ http.post na $ http.get, pamiętaj, że metoda .get akceptuje 2 parametry zamiast 3 ... to jest strata czasu ...;)

kontroler:

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

widok:

<object ng-show="content" data="{{content}}" type="application/pdf" style="width: 100%; height: 400px;"></object>
Jan Tchärmän
źródło
responseType:'arraybuffer', właśnie zaoszczędziłem kilka godzin snu! +1
svarog
jak wywołać zapis zamiast wydrukować go w html?
fdrv
dziękuję, to zaoszczędziło mi kilka godzin, można również wymienić $scope.content = $sce.trustAsResourceUrl(fileURL);z $window.open(fileURL, '_self', '');i otwórz plik na pełnym ekranie.
Tavitos
9

Napotkałem trudności podczas używania „window.URL” w przeglądarce Opera Browser, ponieważ spowodowałoby to „undefined”. Ponadto w przypadku window.URL dokument PDF nigdy nie otwierał się w przeglądarce Internet Explorer i Microsoft Edge (czekałby na zawsze). Wymyśliłem następujące rozwiązanie, które działa w IE, Edge, Firefox, Chrome i Opera (nie testowałem z 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);
    }
}

Daj mi znać, jeśli to pomogło! :)

Manuel Hernandez
źródło
Takie podejście nie powoduje otwarcia dokumentu PDF w oknie przeglądarki w przeglądarce IE, ale zachęca użytkownika do jego pobrania. Czy jest jakaś praca nad tym?
sdd,
1
Powyższy kod służy do pobrania pliku PDF i umożliwienia domyślnej aplikacji PDF Reader przejęcie go, aby go otworzyć. Działa nawet dobrze na urządzeniach mobilnych. Powodem jest to, że chociaż mogłem otworzyć plik PDF w niektórych przeglądarkach, nie mogłem go otworzyć w innych. Dlatego pomyślałem, że najlepiej będzie mieć rozwiązanie, które będzie działać we wszystkich przeglądarkach (w tym przeglądarkach mobilnych), aby pobrać plik PDF.
Manuel Hernandez
Aby wyświetlić plik PDF w nowej karcie, możesz użyć następującego kodu: window.open (reader.result, '_blank');
samneric
6

Dodanie responseType do żądania utworzonego z angular jest rzeczywiście rozwiązaniem, ale dla mnie nie zadziałało, dopóki nie ustawiłem responseType na blob , a nie na arrayBuffer. Kod jest oczywisty:

    $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
źródło
2
właściwie, 'blob'czcionką można pisać krócej: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response));Nie trzeba tworzyćBlob
Alena Kastsiukavets
0

Przez ostatnie kilka dni zmagałem się z pobieraniem plików PDF i obrazów, wszystko, co udało mi się pobrać, to proste pliki tekstowe.

Większość pytań ma te same elementy, ale ustalenie właściwej kolejności zajęło trochę czasu.

Dziękuję @Nikolay Melnikov, Twój komentarz / odpowiedź na to pytanie sprawiło, że zadziałało.

W skrócie, oto moje wywołanie backendowe usługi 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'
    });
  }

Z mojego kontrolera:

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
źródło
0

Najnowsza odpowiedź (dla 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
źródło
-1

Propozycja kodu, którego właśnie użyłem w moim projekcie przy użyciu 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
źródło
1
proszę dodać też krótki opis.
Farhana