Showing PDF (Blob) on iOS received from my angularjs application - A how-to guide

My Angular 1.5 app connects to a backend server running Java, Tomcat, and Spring via REST.

One of the REST services generates PDF files and sends them to clients. While this works well on desktop browsers like Firefox and Chrome, I'm facing an issue where the PDF content is not visible on iOS devices such as iPads, regardless of the browser being used (Chrome or Safari).

Below is the Angular code snippet:

$http.get("/displayPdf", {responseType: 'arraybuffer', params: {id: 1}}).
 success(function(data) {
   var blob = new Blob([data], {type 'application/pdf'});
   var objectUrl =  window.URL.createObjectURL(blob);
   window.open(objectUrl);
 }
);

The corresponding Spring/Jax-RS code is as follows:

@GET
@Path("displayPdf")
@Produces("application/pdf")
Response displayPdf(@QueryParam("id") Long id) {
  byte[] bytes = service.generatePdf(); 
  return javax.ws.rs.core.Response.ok().
    entity(bytes).
    header("Content-Type", "pdf").
    header("Content-Disposition", "attachment; filename='test.pdf'").
    build();
}

I have looked into solutions such as the one mentioned here (AngularJS: Display blob (.pdf) in an angular app), but have not found a suitable fix.

If anyone has any insights on how I can resolve this issue and successfully display generated PDFs to iPad/iPhone users, I would greatly appreciate it.

Thank you!

Answer №1

Unfortunately, none of the solutions mentioned previously worked in my case.

The main issue was related to the URL not being retrieved correctly on iOS. The following code snippet resolved the issue:

window.URL = window.URL || window.webkitURL;

Even with this fix, the problem persisted on Chrome iOS and Opera iOS. After extensive research online and drawing inspiration from various discussions on Stack Overflow such as:

  • Blob createObjectURL download not working in Firefox (but works when debugging)
  • How to open Blob URL on Chrome iOS
  • Display blob (.pdf) in an Angular app

I ultimately arrived at a solution that worked across all iOS browsers except for Firefox on iOS:

if (window.navigator.msSaveOrOpenBlob) { //IE 11+
  window.navigator.msSaveOrOpenBlob(blob, "my.pdf");
} else if (userAgent.match('FxiOS')) { //FF iOS
  alert("Cannot display on FF iOS");
}
} else if (userAgent.match('CriOS')) { //Chrome iOS
  var reader = new FileReader();
  reader.onloadend = function () { $window.open(reader.result);};
  reader.readAsDataURL(blob);
} else if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)) { //Safari & Opera iOS
  var url = $window.URL.createObjectURL(blob);
  window.location.href = url;
}

Answer №2

To integrate the following block of code into your application for making a $http call, follow these steps:

    $http.get("/retrievePdf", {responseType: 'arraybuffer', params: {id: 1}}).success(function(data) {
        var blob = new Blob([data], {type 'application/pdf'});
        var anchor = document.createElement("a");

        if(navigator.userAgent.indexOf("Chrome") != -1 || navigator.userAgent.indexOf("Opera") != -1){
            $window.open(URL.createObjectURL(file,{oneTimeOnly:true}));
        } else if(navigator.userAgent.indexOf("iPad") != -1){
            var fileURL = URL.createObjectURL(file);
            anchor.download="myPDF.pdf";
            anchor.href = fileURL;
            anchor.click();
        } else if(navigator.userAgent.indexOf("Firefox") != -1 || navigator.userAgent.indexOf("Safari") != -1){
            var url = window.URL.createObjectURL(file);
            anchor.href = url;
            anchor.download = "myPDF.pdf";
            document.body.appendChild(anchor);
            anchor.click();
            setTimeout(function(){
                document.body.removeChild(anchor);
                window.URL.revokeObjectURL(url);  
            }, 1000);
        }
    });

Answer №3

I have a similar setup to yours, but I approach building my PDF in a different way. Unfortunately, I haven't been able to test it with iOS yet, but hopefully, this method will be helpful:

$http({ url: $scope.url,
            method: "GET",
            headers: { 'Accept': 'application/pdf' },
            responseType: 'arraybuffer' })
        .then(function (response) {
            var file = new Blob([response.data], {type: 'application/pdf'});
            var fileURL = URL.createObjectURL(file);
            $scope.pdfContent = $sce.trustAsResourceUrl(fileURL);
        });//end http

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The input text in the Typeahead field does not reset even after calling this.setState

As I work on creating a watchlist with typeahead functionality to suggest options as the user types, I encountered an issue where the text box is not resetting after submission. I attempted the solution mentioned in this resource by calling this.setState( ...

What would be the optimal approach for displaying an image that is stored remotely?

I have been exploring this topic, but have yet to find a clear answer - sendAsynchronousRequest vs. dataWithContentsOfURL. Which approach is more efficient, elegant, and safer? - (void)loadImageForURLString:(NSString *)imageUrl { self.image = nil; ...

What is causing .then() to not wait for the promise to resolve?

I'm currently delving into an Angular project, and I must admit, it's all quite new to me. My confusion lies in the fact that the .then() function doesn't seem to be waiting for the promises to resolve. Could this have something to do with ...

What is the process for adjusting the height of a scrollbar thumb?

Is it possible to set a fixed height for the scrollbar and adjust the amount of content scrolled accordingly with CSS? Here is my current CSS code: ::-webkit-scrollbar { width: 30px; } /* Track */ ::-webkit-scrollbar-track { box-shadow: inset ...

How to URL encode NSStrings containing emoticons and emojis?

I am currently facing a challenge with handling the content of a UITextField that includes special characters and emojis, in order to successfully pass it as a GET request parameter to a PHP service. When I don't encode the string at all, emojis disp ...

Empty refreshToken in aws-amplify's javascript

Utilizing aws-amplify, my configuration looks like this: Amplify.configure({ Auth: { region: config.aws.region, identityPoolRegion: config.aws.region, userPoolId: process.env.userPoolId, userPoolWebClientId: process.env.appClientI ...

Is there a way to position the weather icon beside the weather condition?

My icon is hanging low on the left corner of the screen. I'm looking for a quick way to move it next to the weather condition (right below Your Location). Access Codepen link <div class="container"> <h1 class=" text-center"> Your Loc ...

Is there a way to set a value for an attribute in a form post submit button click?

I need to update the value of a form when the user selects "null" <form name="myForm" action="formProcess.php" method='post' onSubmit="return validateForm()"> <label for="venue">Venue:</label> <select name="venue"> ...

What is the reason that JavaScript does not run the code sequentially?

Looking for a solution with a simple function like this: function getArticles(page){ page = page || 1; loading = false; var articlesCache = getArticlesCache(page); if(articlesCache){ articles = articlesCache.data; }else{ make a request a ...

A guide on organizing nested JSON objects in JavaScript

I am currently using JavaScript to retrieve JSON data that looks like this: [{ "data": { "serialNumber": "12345678", "loopCount": 2, "temperature3": 22.74921781259558, "temperature2": 21.459065450414467, "temper ...

Calculating the median in JavaScript utilizing a for loop

Currently, I am in the process of learning JavaScript. My goal is to calculate the median of a set of numbers that I input through a prompt when I click the button labeled "find median". function CalculateMedia() { var n = prompt("Enter the number of e ...

Using ng-show and ng-model simultaneously on the same $scope variable is not supported

I'm attempting to display a span element with some $scope variable only when it is not null or empty. I realize that I can achieve this using ng-model alone, but I am confused why the following code does not work: <span ng-show="x !== null" ng-mo ...

Blockage preventing text entry in a textarea

To enhance the basic formatting capabilities of a textarea, I implemented a solution where a div overlay with the same monospace font and position is used. This approach allows for displaying the text in the div with different colors and boldness. However ...

Issue encountered when trying to display a view in Laravel using PHP

tag, I have implemented a search field in my master blade, integrating the TypeAhead autocomplete plugin. Below are the routes used for this functionality: Route::get('search',array('as'=>'search','uses'=>&apo ...

What purpose does this particular express variable serve?

I am currently diving into the world of JavaScript, with a basic programming background to boot. However, I have always stumbled when it comes to grasping OOPs concepts. For instance, we start by importing what I believe is the express module through &apo ...

Warning: The core schema has detected an unknown property `color` for the component or system `undefined` in Aframe + Vuejs. This issue was flagged within 10 milliseconds in

I am facing some challenges trying to integrate Aframe and vuejs seamlessly, as the console is displaying warning messages. It seems like Aframe is validating the attribute values before vue has a chance to modify them. Warning messages core:schema:warn ...

Display a loading spinner on the browser while the form is being submitted

My current project involves using AJAX to retrieve data and populate a form. The data being fetched is quite large, resulting in a delay as it is fetched from the database and filled into the form fields. During this process, I display a loading icon to in ...

Retrieving JSON information stored in a JavaScript variable

I'm feeling a bit embarrassed to admit it, but I am still learning the ropes when it comes to Javascript development. I've hit a roadblock and could really use some help from the experts here. Thank you in advance for all the assistance this comm ...

Seeking assistance with prototyping JS/AJAX features

For my current project, I have been utilizing PrototypeJS. However, today I ran into a problem. I am working on creating a contact list for a module, where contacts can be added via a form or removed with a link. Below is the HTML code for the removal li ...

Incorporate Javascript to smoothly transition a div into view, display it for a specified duration, gradually fade it out, and ultimately delete

I am excited to experiment with toast notifications by creating them dynamically. Each toast has a unique id number and I increment a counter every time a new one is created. The current functionality includes the toast sliding down, staying visible for 3 ...