Angular 4.x + Cordova : FileReader fails silently (white screen of death)

Viewed 2060

I have an Angular 4.3 + Cordova application that used to work very well. But now, I get a blank screen on app start-up, and nothing happens any more.

After digging a while I realized where it comes from :

my home page is protected by a CanActivate guard that will check some file-system-persisted preferences and redirect the user to another page if this is the first run or if a required preference is missing, to fill-in the required properties.

So the launch of the app depends on my CanActivate guard that depends on a PreferenceService that itself depends on a FileSystemService that I implemented myself. The problem is that when I try to read the file where user's preferences are stored, not a single callback is fired, nothing happen, not even an error.

this is the part of my FileSystemService that fails without any error :

read(file: FileEntry, mode: "text" | "arrayBuffer" | "binaryString" | "dataURL" = "text"): Observable<ProgressEvent> {
    return this.cdv.ready.flatMap(() => {
        return Observable.create(observer => {
            file.file(file => {
                let reader = new FileReader();
                reader.onerror = (evt: ErrorEvent) => {
                    this.zone.run(() => observer.error(evt)); //never triggered
                };
                reader.onload = (evt: ProgressEvent) => {
                    this.zone.run(() => observer.next(evt)); //never trigerred
                };
                switch (mode) {
                    case "text":
                        reader.readAsText(file);
                        break;
                    case "arrayBuffer":
                        reader.readAsArrayBuffer(file);
                        break;
                    case "binaryString":
                        reader.readAsBinaryString(file);
                        break;
                    case "dataURL":
                        reader.readAsDataURL(file);
                        break;
                }
            });
        });
    });
}

Why does this even happen and how can I deal with that so my callbacks get triggered ?

3 Answers

Something late to the party but I had to fix an Ionic3/Angular4 project with this exact problem and I found that the answer from @n00dl3 was on point but there is something of a race condition when an FileReader instance is created in a global service. Because sometimes zone did not patched yet the FileReader window object so no __zone_symbol__OriginalDelegate is found.

So what I did to always get the correct class is a little factory function that returns a FileReader instance:

function HackFileReader(): FileReader {
  const preZoneFileReader = ((window as any).FileReader as any).__zone_symbol__OriginalDelegate;
  if (preZoneFileReader) {
    console.log('%cHackFileReader: preZoneFileReader found creating new instance', 'font-size:3em; color: red');
    return new preZoneFileReader();
  } else {
    console.log('%cHackFileReader: NO preZoneFileReader was found, returning regular File Reader', 'font-size:3em; color: red');
    return new FileReader();
  }
}

and to use it just do :

const reader = HackFileReader();

I hope it helps somebody

If you're using ionic/cordova, there is no need for the HackFileReader solution from @disante (which I actually used)

Two things you need to do, first off is make sure you have the most current zone.js.

npm install --save zone.js@latest

Second you need to ensure that your index.html adds cordova.js AFTER build/polyfills.js

Related