Angular 2 encode image to base64
Asked Answered
S

4

27

I want to encode the uploaded files to base64 so that I can pass them to the request. The problem is that I'm using Angular 2 with Typescript and I couldn't find any info on how to do that. I found that in Javascript it can be done with canvas but I don't know how could I implement the code in Typescript.

<input type="file" class="form-control" accept="image/*" multiple
    [(ngModel)]="spot.images" name="images">
Schutzstaffel answered 1/9, 2016 at 13:32 Comment(3)
Any reason you aren't using FileReader.readAsDataURL()?Anagoge
any solution ? I need this tooUncalledfor
Working Code: stackblitz.com/edit/…Doviedow
S
74

So I find the solution:

compontent.ts

changeListener($event) : void {
  this.readThis($event.target);
}

readThis(inputValue: any): void {
  var file:File = inputValue.files[0];
  var myReader:FileReader = new FileReader();

  myReader.onloadend = (e) => {
    this.image = myReader.result;
  }
  myReader.readAsDataURL(file);
}

component.html

<input type="file" accept="image/*" (change)="changeListener($event)">
Schutzstaffel answered 8/9, 2016 at 10:55 Comment(4)
This works perfectly. I was even able to wrap it in a component that ties into ngmodel to use it as a form control. See my answer if you're interested.Scorecard
Good day! How about in multiple file?Lavoie
Awesome! I created a StackBlitz with your solution: stackblitz.com/edit/encode-base64-imgPosh
i am getting an error ReferenceError: e is not definedHunyadi
S
8

Here is the answer above wrapped in a reuseable component that ties into ngmodel.

import { NgModule, Component, Input, Output, ElementRef, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { FormsModule } from "@angular/forms";

@Component({
    selector: 'file-upload',
    template:  `<input *ngIf="showFileNameInput" id="uploadFile" class="upload-file form-control" placeholder="Choose File" [(ngModel)]="selectedFileName" disabled="disabled" />
                <div class="fileUpload btn btn-primary">
                    <span>{{uploadButtonText}}</span>
                    <input type="file" class="upload" accept="*" (change)="changeListener($event)">
                </div>`,
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => FileUploadComponent),
            multi: true
        }
    ]
})
export class FileUploadComponent implements ControlValueAccessor {
    selectedFileName: string = null;
    @Input() showFileNameInput: boolean;
    @Input() uploadButtonText: string;

    writeValue(value: any) {
       //Handle write value
    }
    propagateChange = (_: any) => { };
    registerOnChange(fn) {
        this.propagateChange = fn;
    }
    registerOnTouched() { }

    changeListener($event): void {
        // debugger; // uncomment this for debugging purposes
        this.readThis($event.target);
    }
    readThis(inputValue: any): void {
        // debugger; // uncomment this for debugging purposes
        var file: File = inputValue.files[0];
        var myReader: FileReader = new FileReader();

        myReader.onloadend = (e) => {
            this.propagateChange(myReader.result);
            this.selectedFileName = file.name;
        }
        myReader.readAsDataURL(file);
    }
}

@NgModule({
    declarations: [
        FileUploadComponent
    ],
    imports: [FormsModule],
    exports: [
        FileUploadComponent
    ]
})
export class FileUploadModule { }

Which can be used like

<file-upload [showFileNameInput]="true" allowedTypes="image/*" uploadButtonText="Upload File" [(ngModel)]="someProperty"></file-upload> 

Also some css that helped it blend into bootstrap on my site

/********************************/
/* File Upload */
.fileUpload {
    position: relative;
    overflow: hidden;
}

.fileUpload input.upload {
    position: absolute;
    top: 0;
    right: 0;
    margin: 0;
    padding: 0;
    font-size: 20px;
    cursor: pointer;
    opacity: 0;
    filter: alpha(opacity=0);
}

.upload-file {
    &.form-control {
        width: auto;
        display: inherit;
    }
}
Scorecard answered 13/1, 2017 at 14:45 Comment(7)
how can you pass this to a request? What is the base64 value in here?Potherb
@MixAustria The base64 value is being output to whatever is bound to ngModel or formControl of the component. You can use it like this <file-upload [showFileNameInput]="true" allowedTypes="image/*" uploadButtonText="Upload File" [(ngModel)]]="someProperty"></file-upload> The Base 64 string will be in "someProperty" on your componentScorecard
do you mean someProperty is a variable inside the component? I'm sorry I am really new at this.Potherb
@MixAustria Yes someProperty is a variable in your component.Scorecard
@Scorecard I am getting this error when using this inside the form, If ngModel is used within a form tag, either the name attribute must be set or the form control must be defined as 'standalone' in ngModelOptions, how to use it inside form so that it can be posted over the serveJinni
@InamHassan Give it a name? i.e. something like this: <file-upload name="fileupload1" [showFileNameInput]="true" allowedTypes="image/*" uploadButtonText="Upload File" [(ngModel)]]="someProperty"></file-upload>. Again, someProperty is a variable in your component.Cygnus
There's a typo in @Josh's answer & comment - [(ngModel)]]="someProperty" should be [(ngModel)]="someProperty"Faeroese
P
5

You can create a Wrapper class for the FileReader class to return an observable.Subscribe for it and on success use the .target to get the base64 for do whatever you want.

import {ReplaySubject} from "rxjs/ReplaySubject";
import {Observable} from "rxjs/Observable";

export class ObservableFileReader {

  constructor(){}

  public readFile(fileToRead: File): Observable<MSBaseReader>{
    let base64Observable = new ReplaySubject<MSBaseReader>(1);

    let fileReader = new FileReader();
    fileReader.onload = event => {
        base64Observable.next(fileReader.result);
    };
    fileReader.readAsDataURL(fileToRead);

    return base64Observable;
   }
}
Potsherd answered 1/9, 2016 at 15:10 Comment(1)
Could you please add a code snippet of this? I don't get the idea hereSchutzstaffel
T
3

A possible solution using Rxjs

  import { fromEvent } from 'rxjs';
  import { pluck } from 'rxjs/operators';

   onUploadImage(event) {
    if (event.target.files.length > 0) {
      const fileReader = new FileReader();
      let imageToUpload = event.target.files.item(0);
      this.imageToBase64(fileReader, imageToUpload)
        .subscribe(base64image => {
          // do something with base64 image..
        });
    }
  }

  imageToBase64(fileReader: FileReader, fileToRead: File): Observable<string> {
    fileReader.readAsDataURL(fileToRead);
    return fromEvent(fileReader, 'load').pipe(pluck('currentTarget', 'result'));
  }
Tribrach answered 19/6, 2019 at 20:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.