Unique Version: When utilizing custom window.FileReader methods, Angular zone execution is bypass

Upon transitioning an Ionic/Angular project from Cordova to Capacitor, I found it necessary to override the default window.FileReader in order to successfully execute the onload() method. Here is the approach I took (https://github.com/ionic-team/capacitor/issues/1564):

constructor(
    appRef: ApplicationRef
  ) {
    class IonicFileReader extends window.FileReader {
      constructor() {
        super();

        // Various attempted solutions not achieving desired results

        const zoneOriginalInstance = (this as any)[
          '__zone_symbol__originalInstance'
        ];
        return zoneOriginalInstance || this;
      }

      // Various attempted solutions not achieving desired results

    }

    // Various attempted solutions not achieving desired results

    window.FileReader = IonicFileReader;
  }

I made the override within the constructor of the AppModule to allow for passing the ApplicationRef and triggering the change detection mechanism. Unfortunately, none of the solutions, except for solution number 4 which was deemed unacceptable, yielded the desired outcome.

Initiating change detection should occur at this point within the function:

function blobToText(blob: any): Observable<string> {
    return new Observable<string>((observer: any) => {
        if (!blob) {
            observer.next("");
            observer.complete();
        } else {
            let reader = new FileReader();
            reader.onload = event => {
                observer.next((<any>event.target).result);
                observer.complete();
              
                // CHANGE DETECTION SHOULD BE FIRED HERE

                // Various attempted solutions not achieving desired results
            };
            reader.readAsText(blob);
        }
    });
}

Answer №1

After incorporating a file plugin into the Ionic framework, I encountered an issue with the FileReader class losing its reference. Fortunately, I found a solution that not only works for Ionic but also for Angular.

By adding the following code to your root application module:

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initReaderOverride,
      deps: [ReaderService],
      multi: true
    }
  ]
})
export class RootModule {}

I utilized a singleton service within a factory function to initialize the override:

export function initReaderOverride (readerService: ReaderService): () => void {
  return () => readerService.init();
}

The implementation of the service:

@Injectable({
  providedIn: "root"
})
export class ReaderService {
  private get windowRef (): Window & typeof globalThis {
    return this.document.defaultView
  }

  constructor (@Inject(DOCUMENT) private readonly document: Document) { }

  init (): void {
    (<any>this.windowRef).FileReader = RealFileReader
  }
}

class RealFileReader extends (<any>window).FileReader {
  constructor () {
    super()
    const zoneOriginalInstance = (this as any)["__zone_symbol__originalInstance"]
    return zoneOriginalInstance || this
  }
}

This workaround proved to be a lifesaver for my mobile functionality and kept the client's frustrations at bay. Hopefully, it can benefit others facing a similar issue!

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

Adding existing tags to Select2 in Angular2 can be accomplished by following these steps:

HTML: <select data-placeholder="Skill List" style="width:100%;" class="chzn-select form-control" multiple="multiple"> <option *ngFor="#skill of allSkills" [ngValue]="skill">{{skill}} </option> </select> TS: allSkills = [& ...

Meteor: How to upload an image file by utilizing the FileReader on the client side and Npm requiring "fs" on the server side

I am facing difficulties trying to upload an image file to my public/ directory using a standard <input type="file"> element. This is the code snippet causing issues: "change .logoBusinessBig-upload":function(event, template){ va ...

What is the best way to combine data from two rows into one row?

Can someone help me with merging 2 sets of Line data into a single row for each entry? For example, the 'Green Bay Packers @ Chicago Bears' row should display '+3.5000 and -3.5000', while 'Atlanta @ Minnesota' should show &apo ...

Transferring information from a client-side JavaScript to a Node.js Express server and receiving back

I'm currently working on implementing an upvote and downvote system in nodejs. The functionality for upvoting and downvoting will be handled by client-side JavaScript, which will then send the data to the server for storage. I'm curious to know ...

Using a Typescript typeguard to validate function parameters of type any[]

Is it logical to use this type of typeguard check in a function like the following: Foo(value: any[]) { if (value instanceof Array) { Console.log('having an array') } } Given that the parameter is defined as an array o ...

Listening to a sequence of mp3 tracks consecutively

I'm currently working on a project that involves playing a series of mp3 files consecutively. However, I've encountered an issue with my code snippet below: Here's the code snippet: function playAudio(){ var au = document.getElementById( ...

Fading in and out occurs several times while scrolling through the window

My goal is to update the logo image source with a fadeIn and fadeOut effect when scrolling up or down. The issue I'm facing is that the effect happens multiple times even after just one scroll, resulting in the logo flashing many times before finally ...

What is the best way to showcase a local image in the console using nwjs?

I am currently developing a desktop application using NW.js (node-webkit). In relation to this topic google chrome console, print image, I am attempting to display an image in the console. Following the suggestion from the aforementioned topic, the follo ...

Can we access an element within the document using its context?

One common method to access an element is by using its id: <div id="myId"></div> <script type="text/javascript"> $(document).ready(function(){ $('#myId').something(); }); </script> However, there are inst ...

How can we enhance our proxyURL in Kendo UI with request parameters?

As outlined in the Kendo UI API documentation, when using pdf.proxyURL with kendo.ui.Grid, a request will be sent containing the following parameters: contentType: Specifies the MIME type of the file base64: Contains the base-64 encoded file content fil ...

Resolving problem with saving an Array of Objects due to parsing issues with empty objects

I'm experiencing a peculiar problem with the Parse .save method. Saving individual Objects and Arrays of strings works seamlessly. However, when attempting to save an Array of Objects like: [{"pos": 10101, "id": 2312}, {...}, {...}], I encounter issue ...

Display dynamic content with AJAX in a pop-up modal window while also updating the

Currently, when I click on a button, a modal pops up with data retrieved from an ajax action that has been given an id. I would like the URL to update when this happens. Additionally, I want the option for the modal to preload if someone directly accesses ...

Using browser's local storage: deleting an entry

I recently came across a straightforward to-do list. Although the inputs are properly stored in local storage, I encountered issues with the "removing item" functionality in JS. Even after removing items from the HTML, they still persist in local storage u ...

Take away limitations from JavaScript code

I stumbled upon this code snippet online and I'm attempting to eliminate the Name must be letters only and min 3 and max 20 restriction. The name provided can have less than 3 characters and may include numbers. My JavaScript skills are still in the l ...

What is the best approach for sending a binary image post request to an API using nodejs?

I am receiving the image binary in this manner: axios.get("image-url.jpg") Now, I want to utilize the response to create a new POST request to another server const form = new FormData(); const url = "post-url-here.com"; form.appe ...

What are the key distinctions between an arrow function, a class, and a traditional function?

Is there a way to distinguish between the following three elements in ES6 using its reference? let x = i => i+1; class y { constructor(i) { this._i=i+1; } get i(){ return this._i;} } function z(i) { return i+1; } For example: test(x) //=> ' ...

Discovering country code details through the Geonames service API rather than relying on the HTML5 location object

My goal is to retrieve the country code of the user's current location using the Geonames Service API. However, it seems that the API only provides a two-letter country code instead of a three-letter one, which is what I require. To work around this i ...

What is the best method to modify the accurate phone number within my script?

I need help with a text format script. link HTML CODE: <label for="primary_phone">Primary Phone Number<span class="star">*</span></label> <br> <input type="text" name="primary_phone" id="primary_phone" class="_phone requ ...

Ensuring that all checkboxes have been selected

I have 5 checkboxes all with the attribute name set as relative-view. To confirm that all of them are checked, I know how to verify the first and last one: expect(element.find('input[name="relative-view"]').first().prop("checked")).toBe(true); ...

Italian calendar conversion for the react-multi-date-picker library

I recently integrated the react-multi-date-picker into my project, utilizing the multiple mode feature. However, I encountered an issue when trying to display the Italian calendar based on the language setting. Despite using locale="it", the calendar was n ...