Как отобразить blob (.pdf) в приложении AngularJS

106

Я пытаюсь отобразить файл PDF, который я получаю в виде капли из $http.postответа. PDF-файл должен отображаться в приложении, <embed src>например, с использованием.

Я наткнулся на пару сообщений в стеке, но мой пример почему-то не работает.

JS:

Согласно этому документу , я продолжил и попробовал ...

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

Теперь, fileURLнасколько я понимаю, создается временный URL-адрес, который блог может использовать в качестве ссылки.

HTML:

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

Я не уверен, как справиться с этим в Angular, идеальной ситуацией было бы (1) назначить его области, (2) `` подготовить / перестроить '' blob в pdf (3) передать его в HTML, используя, <embed>потому что я хотите отобразить его в приложении.

Я занимаюсь исследованиями больше суток, но почему-то не могу понять, как это работает в Angular ... И давайте просто предположим, что библиотеки просмотра PDF-файлов не были доступны.

Симо Д'ло Мафуксвана
источник
Привет, D'lo DeProjuicer, удалось ли вам решить проблему создания PDF с помощью angular?
Раймонд Накамп
@michael D'lo DeProjuicer Что нужно сделать для того же случая в angular 2?
Моника

Ответы:

214

Прежде всего вам нужно установить responseTypeзначение arraybuffer. Это необходимо, если вы хотите создать большой двоичный объект данных. См. Sending_and_Receiving_Binary_Data . Итак, ваш код будет выглядеть так:

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

Следующая часть заключается в том, что вам нужно использовать сервис $ sce, чтобы Angular доверял вашему URL-адресу. Сделать это можно так:

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

Не забудьте внедрить сервис $ sce .

Если все это сделано, вы можете встроить свой pdf-файл:

<embed ng-src="{{content}}" style="width:200px;height:200px;"></embed>
Майкл
источник
9
Для меня это не сработало в Chrome (35.0.1916.114 м). Решено с помощью <object> вместо <embed>: <object data = "{{content}}" type = "application / pdf"> </object>
HoffZ
2
Для меня (AngularJS 1.25) мне пришлось сделать: новый Blob ([response.data]
Мартин Коннелл
2
@HoffZ: Я заменил метод ярлыка $http.getна полный, указав responseTypeполе: { 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' }И работает :)
Николай Мельников
1
Для меня единственный способ заставить его работать - это создать каплю response.dataвместо response, например:var file = new Blob([response.data], {type: 'application/pdf'});
Алекос Филини
1
@ yosep-kim, это не работает в IE, потому что объект URL не существует в IE: caniuse.com/#search=URL
Карлос
32

Я использую AngularJS v1.3.4

HTML:

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

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

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 - 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;
    }
Стефан ГРИЛЬОН
источник
какая версия сафари? window.URL хорош в Safari 9 и после: caniuse.com/#search=createObjectURL
Stéphane GRILLON
Я тестировал и проверял на своем MacBook Pro и Safari 9.0.2.
Стефан ГРИЛЬОН
То же самое, MacBook el captain. window.URL.createObjectURL (файл); Я не понимаю, в чем проблема, но код не работает. Может я что-то не так делаю. Любое спасибо. У меня нет времени проверить, что не работает, и использовать
FileSaver.js
если ваше приложение онлайн, опубликуйте свой URL, пожалуйста? у вас такая же Back-End?
Стефан ГРИЛЬОН
Атрибут загрузки не поддерживается в сафари. caniuse.com/#search=download
Бисванат
21

Предложения Майкла работают как шарм для меня :) Если вы замените $ http.post на $ http.get, помните, что метод .get принимает 2 параметра вместо 3 ... это то, на что я потратил зря мое время ...;)

контроллер:

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

Посмотреть:

<object ng-show="content" data="{{content}}" type="application/pdf" style="width: 100%; height: 400px;"></object>
Ян Чярман
источник
responseType:'arraybuffer', только что сэкономил мне пару часов сна! +1
svarog 04
как запустить сохранение вместо того, чтобы распечатать его в html?
fdrv
спасибо, это спасло мне пару часов, вы можете также заменить $scope.content = $sce.trustAsResourceUrl(fileURL);с $window.open(fileURL, '_self', '');и открыть файл на весь экран.
Тавитос
9

Я столкнулся с трудностями при использовании "window.URL" в браузере Opera, так как это привело бы к "undefined". Кроме того, с помощью window.URL документ PDF никогда не открывался в Internet Explorer и Microsoft Edge (он будет ждать вечно). Я придумал следующее решение, которое работает в IE, Edge, Firefox, Chrome и Opera (не тестировалось с 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);
    }
}

Сообщите мне, помогло ли это! :)

Мануэль Эрнандес
источник
При таком подходе PDF-документ не открывается в окне браузера IE, а пользователю предлагается загрузить его. Есть ли какое-нибудь решение?
sdd
1
Приведенный выше код предназначен для загрузки файла PDF и позволяет приложению PDF Reader по умолчанию открыть его. Он хорошо работает даже на мобильных устройствах. Причина в том, что хотя мне удавалось открыть PDF-файл в некоторых браузерах, я не мог открыть его в других. Поэтому я подумал, что лучше иметь решение, которое будет работать во всех браузерах (включая мобильные браузеры) для загрузки файла PDF.
Мануэль Эрнандес
Вы можете использовать следующий код для просмотра PDF-файла в новой вкладке: window.open (reader.result, '_blank');
samneric 09
6

Добавление responseType в запрос, сделанный из angular, действительно является решением, но для меня это не сработало, пока я не установил responseType в blob , а не в arrayBuffer. Код говорит сам за себя:

    $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
собственно, 'blob'шрифтом можно написать короче: FileSaver.saveAs(response.data, getFileNameFromHttpResponse(response));Создавать не нужноBlob
Алена
0

Последние пару дней я изо всех сил пытался загрузить PDF-файлы и изображения, все, что мне удалось загрузить, это простые текстовые файлы.

Большинство вопросов имеют одни и те же компоненты, но потребовалось время, чтобы выяснить правильный порядок, чтобы он заработал.

Спасибо @Nikolay Melnikov, ваш комментарий / ответ на этот вопрос заставил его работать.

Вкратце, вот мой бэкэнд-вызов службы 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'
    });
  }

С моего контроллера:

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

Самый последний ответ (для 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

Предложение кода, который я только что использовал в своем проекте с использованием 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
пожалуйста, добавьте немного краткости.
Farhana