displaying an embedded image in angular2

Problem

I'm working on a project in angular2, which involves loading an image from a database directly (base64 encoded). In angular1, one could simply load it as follows:

<img data-ng-src="data:image/jpg;base64,{{entry.img}}" />

where entry.img is the raw image data. However, I have no idea how to do this in angular2. I've tried

<img [src]="data:image/jpg;base64,{{entry.img}}" />

but that doesn't work, as angular still tries to load the image from a URL.

Problem courtesy of: veggiesaurus

Solution

Perhaps you could try this:

<img [src]="'data:image/jpg;base64,'+entry.img" />

assuming that entry is a property of the component and contains an img attribute.

Solution courtesy of: Thierry Templier

Discussion

I have used <img [attr.src]="image.base64"> where my model looks like this

export class ImageModel {
    public alt:string = "";
    public name:string = "";
    public base64:string ='';
}

, but the version of @Thierry works also. I am attaching a part of the component and a piece of html. Maybe you can improve your solution or improve mine :)

HTML

<div class="row">
    <div class="col-xs-12">
        <p class="f-500 c-black m-b-20">Image Preview</p>

        <div class="fileinput fileinput-new" [ngClass]="{'fileinput-exists': fileExists(), 'fileinput-new': !fileExists()}">
            <div class="fileinput-preview thumbnail">
                <img *ngIf="fileExists()" [attr.src]="image.base64">
            </div>
            <div>
                <span class="btn btn-info btn-file">
                    <span class="fileinput-new">Select image</span>
                    <span class="fileinput-exists">Change</span>
                    <input type="file" #fileInp (change)="onFileChange($event)" name="file">
                </span>
                <a href="#" class="btn btn-danger fileinput-exists" (click)="clearImage($event)">Remove</a>
            </div>
        </div>
    </div>
</div>

Component

///<reference path="../../../../../typings/tsd.d.ts"/>

import {Component, OnInit} from 'angular2/core'
import {Router} from 'angular2/router';
import {NgClass} from 'angular2/common';

import {ImageInterface} from './image.interface'
import {ImageService} from './image.service'
import {ImageModel as Image} from './image.model'

import {ImageComponent} from './image.component'

@Component({
    selector: 'create-images-component',
    templateUrl: './angular2/app/images/image-form.component.html',
    providers: [
        ImageService
    ],
    directives: [
        ErrorsComponent,
        NgClass,
    ] })

export class CreateImageComponent implements OnInit {

    public image:ImageInterface = new Image(); 
    public validationErrors;

    constructor(public service:ImageService,
                private _router:Router) {
    }

    /**
     * File input change event
     * @param event
     */
    onFileChange(event) {
        let file = event.target.files[0];
        if (!file) {
            return;
        }
        if ( this.isValidExtension(file) == false ) {
            swal('Invalid file format!', 'Invalid file Format. Only ' + ImageComponent.ALLOWED_EXTENSIONS.join(', ') + ' are allowed.', 'error');
            return false;
        }
        if (this.isValidFileSize(file) == false) {
            swal('Invalid file size!', 'Invalid file size. Max allowed is : ' + ImageComponent.ALLOWED_SIZE + ', your file is : ' + this.getFileSize(file) + ' Mb' , 'error');
            return;
        }
        console.log(file);

        let reader = new FileReader();
        reader.onload = (e) => {
            this.image.base64 = e.target.result;
        };
        reader.readAsDataURL(file);
    }

    /**
     * Check if file has valid extension
     * @param file
     */
    private isValidExtension(file:File):boolean {
        let allowedExtensions = ImageComponent.ALLOWED_EXTENSIONS;
        let extension = file.name.split('.').pop();
        return allowedExtensions.indexOf(extension) !== -1
    }

    /**
     * Check file size
     * @param file
     * @returns {boolean}
     */
    private isValidFileSize(file) {
        let size = this.getFileSize(file);
        return size < ImageComponent.ALLOWED_SIZE;
    }

    /**
     * GEt file size in Mb
     * @param file
     * @returns {Number}
     */
    private getFileSize(file:File):Number {
        return file.size / 1024 / 1024;
    }

    /**
     * Clear selected image
     * @param ev
     */
    clearImage(ev) {
        ev.preventDefault();
        this.image.base64 = ''
    }

    /**
     * Return if image exists
     * @returns {boolean}
     */
    fileExists() {
        return this.image.base64 && (typeof this.image.base64 !== 'undefined')
    }

    /**
     * Create new image
     */
    onSubmit(form) {
        return this.service.httpPost(this.image)
            .subscribe(
            (res) => {
                if (res.data.errors) {
                    this.validationErrors = res.data.errors;
                }
                if (res.status == "success") {
                    this.successMessage = res.message;
                    swal("Good Job", res.message, "success");
                    this.validationErrors = [];
                } else {
                    this.errorMessage = res.message;
                }
            },
            (error) =>  this.errorMessage = <any>error);
    }

    onCancel() {
        return this._router.navigate(['Images']);
    }

    get diagnostic() {
        return JSON.stringify(this.image);
    }

}

enter image description here

Discussion courtesy of: Ervin Llojku

This recipe can be found in it's original form on Stack Over Flow.