Converting Files To Base64 In Angular

While many API’s allow you to upload files via multi-part POST forms, others prefer to stick with a pure JSON approach and accept uploads in base64 format allowing you to always be sending and receiving JSON. This means that if a user selects a file in your Angular app, you need to be able to convert that file to Base64 before sending it on.

I thought this would be a rather trivial task but there seems to be some really complicated ways to do what seemed simple at first. Many examples tried to use async/await and promises, but Angular really prefers observables. Ontop of that, people were using an API that was not actually about returning base64 strings, but returning DataURI’s which are very close, but some browsers return the result as data:base64here rather than just the base64.

Anyway! The actual code looks like this. In my view I have :

<input type="file" (change)="onFileSelected($event)" />
<br /><br />
base64 Output : <br />
{{base64Output}}

And in my code behind I have :

export class AppComponent  {
  base64Output : string;

  onFileSelected(event) {
    this.convertFile(event.target.files[0]).subscribe(base64 => {
      this.base64Output = base64;
    });
  }

  convertFile(file : File) : Observable<string> {
    const result = new ReplaySubject<string>(1);
    const reader = new FileReader();
    reader.readAsBinaryString(file);
    reader.onload = (event) => result.next(btoa(event.target.result.toString()));
    return result;
  }
}

Notice a few things about the code.

  1. FileReader is event driven. e.g. You can’t say “Load this file” and then immediately get the result. This means that we either have to use promises or observables, because we are using Angular, let’s use observables.
  2. We use a ReplaySubject because we only need to calculate the file once. e.g. If we subscribed multiple times to the same return subject of this method, it doesn’t need to recalculate the base64 since it’s deterministic (The same file is always the same Base64 string).
  3. I saw some guides saying to use reader.readAsDataURL(file), but again this had weird issues in some browsers. It’s better to load the file as per normal, then use the btoa function to actually return Base64 without any other gunk in the response.

Hopefully that makes sense!

Leave a Reply

Your email address will not be published. Required fields are marked *