10

My my requirement is to either display(new tab)/download/embed a PDF in my angular js app on form submit/post.

I do not want the server to return a unique identifier of the generated PDF and than use $window service to open a new window with it's url pointing to a server-side endpoint which returns PDf based on unique identifier. Because I need to generate the pdf on the fly (no storing in file system).

Similar question to this one AngularJS: Display blob (.pdf) in an angular app But it is not working for me.

My controller

angular.module('EvaluationResultsModule').controller('CA_EvaluationResultsCtrl',
    [ '$scope', 'EvaluationResultsService', '$sce', function($scope, EvaluationResultsService, $sce) {

        $scope.showPDF = function() {
            $scope.result = CA_EvaluationResultsService.getEvalutaionResultPDF($scope.evaluationResults);
            $scope.result.$promise.then(function(data) {
                var file = new Blob([data], {
                    type : 'application/pdf'
                });
                var fileURL = URL.createObjectURL(file);
                $scope.pdfContent = $sce.trustAsResourceUrl(fileURL);
            });
        }
    } ]);

My Service

    angular.module('EvaluationResultsModule').factory('EvaluationResultsService', function($resource) {
    return $resource('./api/ca/evaluationResults/:dest', {}, {       
        getEvalutaionResultPDF : {
            method : 'GET',
            params : {
                dest : "getPDF"
            },
            responseType : 'arraybuffer',

        }
    });
});

Rest Controller Method

@RequestMapping(value = "/getPDF", method = RequestMethod.GET)
    public byte[] getEvalutaionResultPDF()  {        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        // Generate PDF using Jasper
        Map<String, Object> model = new HashMap<String, Object>();
        List<User> usersList = null; //populated from Service layer;
        JRBeanCollectionDataSource beanColDataSource = new JRBeanCollectionDataSource(usersList);
        JasperPrint jasperPrint =  jasperPrint = JasperFillManager.fillReport(this.getClass().getClassLoader().getResourceAsStream("A4.jasper"), model, beanColDataSource);
        JasperExportManager.exportReportToPdfStream(jasperPrint, baos);
        return baos.toByteArray();
    }

My response logged in console

response:  Object {data: ArrayBuffer, status: 200, headers: function, config: Object, statusText: "OK"}config: Objectdata: ArrayBufferbyteLength: (...)__proto__: ArrayBufferbyteLength: [Exception: TypeError: Method ArrayBuffer.prototype.byteLength called on incompatible receiver #<ArrayBuffer>]get byteLength: function byteLength() { [native code] }constructor: function ArrayBuffer() { [native code] }slice: function slice() { [native code] }__proto__: Objectheaders: function (name) {resource: Resourcestatus: 200statusText: "OK"__proto__: Object

3 Answers 3

17

I use this code and it works for me:

REST Controller:

@RequestMapping(value = "/api/reports/pdf", method = RequestMethod.GET)
@Timed
public @ResponseBody byte[] getOpenedEventsInPdf(HttpServletResponse response) {
    response.setHeader("Content-Disposition", "inline; filename=file.pdf");
    response.setContentType("application/pdf");
// get file in bytearray from my custom service in backend
    byte[] file = jasperReportsService.getOpenedEventsReport(ReportFormat.PDF);
    return file;
}

JS/Angular Controller;

$scope.getPdf = function(){
  $http.get('/api/reports/pdf', {responseType: 'arraybuffer'})
  .success(function (data) {
    var file = new Blob([data], {type: 'application/pdf'});
    var fileURL = URL.createObjectURL(file);
    window.open(fileURL);
  });
}

HTML fragment:

<a ng-click="getPdf()">Show PDF</a>
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you for concisely answering something that took some time to find.
Thank you so much ... It worked for me with little bit changes... +1.
How to handle exceptions in Rest Controller?
@Guus - you can get it from the response var contentDisposition = response.headers("Content-Disposition"); var filename = (contentDisposition.split(';')[1].trim().split('=')[1]).replace(/"/g, '');
@amallard thank, I found also another way. Using angular-file-saver I can do now FileSaver.saveAs(file, 'my_file_name.pdf');
|
2

For "Browser Compatibility" given code is working properly :

Get the byte array data from beck-end controller side and generate file on js controller side :

Beck-end controller

@RequestMapping(value = "/getPDF", method = RequestMethod.GET)
public byte[] getEvalutaionResultPDF()  {        
        byte[] data = //get byte Array from back-end service
        return data;
}

JS Service

var getPdfFile = function(){
        return $http.get("getPDF", {responseType: 'arraybuffer'});
};

JS controller

$scope.pdfFile = function() {
        service.getPdfFile().then(function (data) {

            //for browser compatibility  
            var ieEDGE = navigator.userAgent.match(/Edge/g);
            var ie = navigator.userAgent.match(/.NET/g); // IE 11+
            var oldIE = navigator.userAgent.match(/MSIE/g); 
            var name = "file";
            var blob = new window.Blob([data.data], { type: 'application/pdf' });

            if (ie || oldIE || ieEDGE) {
                var fileName = name+'.pdf';
                window.navigator.msSaveBlob(blob, fileName);
            }
            else {
                var file = new Blob([ data.data ], {
                    type : 'application/pdf'
                });
                var fileURL = URL.createObjectURL(file);
                var a         = document.createElement('a');
                a.href        = fileURL; 
                a.target      = '_blank';
                a.download    = name+'.pdf';
                document.body.appendChild(a);
                a.click();
            }
        },
        function(error) {
            //error
        });
    };

Comments

0

In the following link, you should find the answer :

AngularJS Display PDF (byte[]) received from Spring(@RestController) + jasper report

In this link you find how display pdf in a iframe using angularjs. The pdf is received from a API rest using spring and jasper report.

1 Comment

Hello, welcome to SO. Please edit your question so that it contains at least a summary of what can be found at that link. Answers containing only a link, without any explanation or comment, might become useless if the link ever became invalid. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.