Mike Summers
Mike Summers

Reputation: 2239

Download pdf with Angular

Trying to download a pdf doc with Angular, we wrote this:

var _config = { headers : {'Accept' : '*/*'},
                responseType : 'arraybuffer'
              };

var success = function(data, status, header, config) {
   $log.debug('Download resume success - type:' + typeof (data));
   var _contentType = (header('Content-Type'));
   var blob = new Blob([ data ], { type : _contentType });
   var url = (window.URL || window.webkitURL).createObjectURL(blob);
   var anchor = angular.element('<a/>');
   anchor.attr({
      href : url,
      target : '_blank',
      download : _fileName
   })[0].click();
}
$http.get(_url, _config).success(success).error(error);

We've tried all permutations of blob and arraybuffer but data always returns as a String with the extended characters 'decoded' which is to say broken.

_contentType is always application/pdf although we've tried forcing it to application/octet-stream as well.

Suggestions and pointers welcomed!

Update

This looks to be a bug someplace between Angular (1.3.15 & 1.4.8) and Chrome's (46.0) XMLHttpRequest implementation where response.data is always returned as a 'decoded' string. Neither Firefox (42) nor IE (10) have this problem and all of the solutions below would most likely work (as does or original solution).

I've reported this as a possible bug to both AngularJS & Chrome.

Upvotes: 0

Views: 27903

Answers (4)

Kihats
Kihats

Reputation: 3520

You need to tell angularjs that you are receiving a binary file in your $http.get or $http.post method. Use {responseType : 'arraybuffer'}.

For example:

$http.post('/pdf/link', requestData, { responseType : 'arraybuffer' }).then(function (data, status, headers) {

        headers = data.headers();
        var contentType = headers['content-type'];
        var linkElement = document.createElement('a');

        try {
            var blob = new Blob([data.data], {type: "application/pdf"});
            var url = window.URL.createObjectURL(blob);

            linkElement.setAttribute('href', url);

            linkElement.setAttribute("download", "mypdf.pdf");

            var clickEvent = new MouseEvent("click", {
                "view": window,
                "bubbles": true,
                "cancelable": false
            });

            linkElement.dispatchEvent(clickEvent);
        } catch (ex) {
            console.log(ex);
        }
    }

Upvotes: 1

dethstrobe
dethstrobe

Reputation: 555

I ran in to this problem myself a few months back. I had to use FileSaver.js to handle it.

So after you install FileSaver.js have your success function look something like this:

function success(response) {
    var blob = new Blob([response.data], { type: "application/pdf"});
    //change download.pdf to the name of whatever you want your file to be
    saveAs(blob, "download.pdf");
}

Upvotes: 3

Lucas
Lucas

Reputation: 10323

Check encoding with your api and in this lines, this worked for me:

            var filepdf = Base64.encode(response.data);
            $scope.filepdf = 'data:application/pdf;base64,' + pdfdata;

CONTROLLER

    $scope.pdfDownloads = function() {
        DownloadPath.get({id: $rootScope.user.account_id}, function (data) {
            $scope.createtext = "Download PDF file";
            $scope.download_pdf_filename = data.filename;
            $scope.getPdf = true;
            $scope.download_dir = file_url;

            $http.get($scope.download_dir).then(function (response) {
                var pdfdata= Base64.encode(response.data);
                $scope.pdfdata= 'data:application/pdf;base64,' + pdfdata;
                $('#pdfanchor').attr({
                    href: $scope.pdfdata,
                    download: $scope.download_pdf_filename
                })
            });                    
        });
    };

HTML

<a href=""ng-click="pdfDownloads()" >Download</a>

EDIT: THIS IS HOW WE STRUCTURED THE RESPONSE (PHP functions)

contentType = 'application/octet-stream';
contentDescription = 'File Transfer';
contentDisposition = 'attachment; filename=' . basename(file_nae);
expires = 0;
cacheControl = 'must-revalidate';
contentLength = filesize($file_name);
body =  base64_encode(file_get_contents($file_name));

Upvotes: 0

Lucas
Lucas

Reputation: 10323

Just change it from your html:

<a target="_self" href="example.com/uploads/file.pdf" download="file_new_name.pdf">

Upvotes: 0

Related Questions