Downloading PDF files on IOS while using Angular often results in the PDF opening in the same

I'm currently utilizing file-saver within my Angular application to retrieve a PDF generated from the backend. The library functions smoothly on desktop and Android devices, but I'm encountering issues with downloading files on iOS. Contrary to what is mentioned on the GitHub page, file-saver does not open the blob in a new window; instead, it opens on the same page (which is undesired). Interestingly, it works seamlessly on Safari by prompting a download dialog without opening the file, but fails on other browsers like Opera, Firefox, and Chrome.

I've experimented with various alternatives such as file-saver, downloadJ, creating an anchor tag with the download attribute, utilizing the application/octet-stream mime-type, and exploring different solutions found online. Unfortunately, most of these methods either do nothing or result in the PDF displaying on the same page rather than initiating a download or opening in a new tab (as specified by file-saver for iOS).

As the PDF is being generated in a Google Cloud Function, I am wondering if there might be a way to bypass the client-side processes and have the browser directly download the file from there.

Is there any alternate approach to downloading PDFs on mobile iOS devices (such as implementing a service worker)?

Appreciate any input or suggestions in advance.

Answer №1

Solution that adheres to the latest Chrome specifications can be found here

Utilizing Vanilla JavaScript

public static downloadFile(url: string): void {
     const xmlHttp = new XMLHttpRequest();
     xmlHttp.onreadystatechange = () => {
       if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
         const blobUrl = window.URL.createObjectURL(xmlHttp.response);
         const e = document.createElement('a');
         e.href = blobUrl;
         e.download = blobUrl.substr(blobUrl.lastIndexOf('/') + 1);
         document.body.appendChild(e);
         e.click();
         document.body.removeChild(e);
       }
     };
     xmlHttp.responseType = 'blob';
     xmlHttp.open('GET', url, true);
     xmlHttp.send(null);
   }

If you're working with Angular, consider this approach.

async downloadBrochure(url: string) {
    try {
      const res = await this.httpClient.get(url, { responseType: 'blob' }).toPromise();
      this.downloadFile(res);
    } catch (e) {
      console.log(e.body.message);
    }
  }

  downloadFile(data) {
    const url = window.URL.createObjectURL(data);
    const e = document.createElement('a');
    e.href = url;
    e.download = url.substr(url.lastIndexOf('/') + 1);
    document.body.appendChild(e);
    e.click();
    document.body.removeChild(e);
  }

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

I couldn't identify the Material import within the child modules of Angular 2

I am facing an issue with importing custom material.ts modules in my app.module.ts file. I am unable to use Material in components declared at the module root level. However, when I create a child module (ClientModule) and declare a component there, Materi ...

Developing a custom function that analyzes two distinct arrays and sends any corresponding pairs to a component

I'm in the process of developing a component that utilizes two arrays. These arrays are then mapped, and the matching pairs are sent down as props to a child component. The goal is to create a list component that retrieves the arrays from the backend ...

Building a single-page app optimized for mobile viewing with Foundation framework

Currently facing an issue with the scaling of the viewport on certain mobile devices when loading new content via ng-include in our responsive website built on Foundation. The problem arises as the width of the page breaks, leading to horizontal scrolling. ...

Guide on altering the background color of a table row depending on the data in its cells with the help of AngularJS

I am looking to dynamically change the background color of a row based on specific cell data. If the first four characters in a table cell match a certain value, I want the entire row to change its color to red. Currently, my code changes the row color ba ...

Ways to utilize a field from an interface as a type of index

interface Mapping { "alpha": (a: string) => void "beta": (b: number) => void } interface In<T extends keyof Mapping> { readonly type: T, method: Mapping[T] } const inHandlers: In<"alpha"> = { type ...

Exploring the differences between an XMLHTTP request and a string and establishing a callback mechanism

After being a silent observer for quite some time, I've finally mustered up the courage to make my first post here, so please be kind... My journey with Javascript has just begun, and although I plan on delving into jQuery eventually, for now, I am f ...

Tips for adding styling to HTML in Vue by entering CSS code into the CodeMirror editor

Is there a way to style HTML by entering CSS code into the Codemirror editor? For instance, if we have the HTML code <head> </head>, how can I apply the CSS code, head{ color : red }, typed in the Codemirror editor to stylize this HTML code? mo ...

Submit button in React form not activating the onSubmit method

Having an issue with a login form code where the submit handler is not being triggered when pressing the Submit button. Any idea what could be causing this? The loginHandler function does not seem to trigger, but the handleInputChange function works fine. ...

Filtering out Objection/Knex query results based on withGraphFetched results

I am working with two models in Objection - "brands" and "offers". Brand: const { Model } = require('objection') class Brand extends Model { static get tableName() { return 'brands' } ...

Is there a way to update the href attribute within the script section in vue.js?

I need to dynamically set the href attribute of a link based on data retrieved from a database and rendered in the methods section. <template v-if="header.value == 'ApplicationName'"> <a id="url" href="#" target="_blan ...

The ngx-translate library could not be located within Ionic Framework 6

Currently, I am looking to incorporate the ngx-translate Pipe for translating my Ionic application. In my app.module.ts file: export function createTranslateLoader(http: HttpClient): TranslateHttpLoader { return new TranslateHttpLoader(http, './ass ...

Manually assigning a value to a model in Angular for data-binding

Currently utilizing angular.js 1.4 and I have a data-binding input setup as follows: <input ng-model="name"> Is there a way to manually change the value without physically entering text into the input field? Perhaps by accessing the angular object, ...

Issue encountered while serializing the `.product` object retrieved from the `getStaticProps` function in NextJS, in conjunction with

I ran into an error message saying "Error: Error serializing .product returned from getStaticProps in "/products/[id]". Reason: undefined cannot be serialized as JSON. Please use null or omit this value." This issue occurred while I was attempting to crea ...

The AngularJS component materializes almost instantaneously

Using AngularJS, I have developed an application where a certain section of code is displayed after the page loads for a split second: <div class="col-sm-4" data-ng-repeat="user in users"> <div class="card"> ...

Need to import Vue component TWICE

My question is simple: why do I need to import the components twice in the code below for it to function properly? In my current restricted environment, I am unable to utilize Webpack, .vue Single File Components, or npm. Despite these limitations, I mana ...

Executing the AngularJS nested controller only once

I am still new to Angularjs and just started working on an app that has several "projects" each with a local menu displayed on specific pages. The main navbar with footer is located in the Index.html: <body ng-app="ysi-app" ng-controller="MainControlle ...

Fetching data from a Django view using a JavaScript AJAX POST call

Utilizing Javascript for an asynchronous request to a Django View, I am able to successfully receive data from the POST request. However, I am encountering issues with returning a confirmation message that the process was successful. Despite expecting xhtt ...

Ways to access subscription value in Angular without relying on async await

Is there a way to extract the value inside the subscribe in Angular? I am dealing with this code snippet: async trackingInfo(trackingNumber) { const foo = await this.userService .trackOrderStatus(trackingNumber) .subscribe((status) => ...

Vuejs tutorial: Toggle a collapsible menu based on the active tab status

I am using two methods called forceOpenSettings() and forceCloseSettings() to control the opening and closing of a collapsible section. These methods function properly when tested individually. However, I need them to be triggered based on a specific condi ...

The implementation of combineSlices in reduxjs/[email protected] is an essential feature for managing

I am struggling to figure out how to properly useAppSelector with LazyLoadedSlices: Here is the setup of my store // @shared/redux/store.ts // comment: https://redux-toolkit.js.org/api/combineSlices // eslint-disable-next-line @typescript-eslint/no-empty ...