3
votes

I am using cordova-plugin-camera within my Ionic 2 app. I can successfully take a photo and then alert the value of selfieImage - this shows me data:image/jpeg;base64, followed by the base64 encoded version of my image - great

takeRegistrationSelfie() {

    Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        cameraDirection: 1        
    }).then((imageData) => {
      // imageData is a base64 encoded string
        this.selfieImage = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });    

}

Within my template I have

<img [src]="selfieImage" *ngIf="selfieImage" />

At this point selfieImage is defined but my image is empty - 10 x 10 pixels, grey border, no image.

Later on in my app I send an ajax request with the image to my backend - this works fine and the image is received correctly.

Why won't the image show within my template?

3

3 Answers

10
votes

I have discovered that I need to use DomSanitizer. With this in place then the image works.

import { DomSanitizer } from '@angular/platform-browser';

In my constructor I have ...

private DomSanitizer: DomSanitizer

And then in my template ...

<img [src]="DomSanitizer.bypassSecurityTrustUrl(selfieImage)" class="registerImage" *ngIf="selfieImage" />

Voila, it works :-)

Edit. I have been asked for a full version of my code. I'll add it below.

register.ts

import { Component } from '@angular/core';
import { NavController, Platform, LoadingController } from 'ionic-angular';
import { Auth, FacebookAuth, User, UserDetails, IDetailedError } from '@ionic/cloud-angular';
import { DashboardPage } from '../dashboard/dashboard';
import { Http } from '@angular/http';
import { URLSearchParams } from "@angular/http"
import { Headers } from '@angular/http';
import { Camera } from 'ionic-native';
import { DomSanitizer } from '@angular/platform-browser';
import 'rxjs/add/operator/map';

/*
  Generated class for the Register page.

  See http://ionicframework.com/docs/v2/components/#navigation for more info on
  Ionic pages and navigation.
*/
@Component({
  selector: 'page-register',
  templateUrl: 'register.html'
})
export class RegisterPage {

  public registerStep: number;

  /* step 0 */
  public candidateFirstName: string;    
  public candidateLastName: string; 
  public candidateDOB: string;
  public candidatePhone: string;  
  public candidateGender: string;    

  /* step 1 */
  public lookupPostcode: string;
  public lookupAddresses: any;
  public addressSelected: boolean = false;

  public candidateAddress1: string;  
  public candidateAddress2: string;  
  public candidateTown: string;  
  public candidatePostcode: string;        

  /* step 2 */  
  public selfieImage: string;   

  /* step 3 */    
  public passportImage: string; 

  public registerResponse: any = {};

  constructor(public platform: Platform, public navCtrl: NavController, public http: Http, public user: User, public auth:Auth, public loadingCtrl: LoadingController, private DomSanitizer: DomSanitizer) {
    this.registerStep = 0;
  }

  doRegistration(step) {

    if(step == 1) {
      this.registerStep = 1;    
    }
    else if(step == 2) {
      this.registerStep = 2;  
    }  
    else if(step == 3) {
      this.registerStep = 3;    
    }  
    else if(step == 4) {
      this.registerStep = 4;    
    }  
    else if(step == 5) {

      var headers = new Headers();
      headers.append('Content-Type', 'application/x-www-form-urlencoded');  

    let urlSearchParams = new URLSearchParams();
    urlSearchParams.append('action', 'register');
    urlSearchParams.append('candidateFirstName', this.candidateFirstName);
    urlSearchParams.append('candidateLastName', this.candidateLastName);  
    urlSearchParams.append('candidateDOB', this.candidateDOB);      
    urlSearchParams.append('candidatePhone', this.candidatePhone);  
    urlSearchParams.append('candidateGender', this.candidateGender);                    

    urlSearchParams.append('candidateAddress1', this.candidateAddress1);    
    urlSearchParams.append('candidateAddress2', this.candidateAddress2);    
    urlSearchParams.append('candidateTown', this.candidateTown);    
    urlSearchParams.append('candidatePostcode', this.candidatePostcode);

    urlSearchParams.append('selfieImage', encodeURIComponent(this.selfieImage));
    urlSearchParams.append('passportImage', encodeURIComponent(this.passportImage));                                        

    urlSearchParams.append('candidateHash', this.user.id);
    let body = urlSearchParams.toString()

      this.http.post('http://www.example.com/api/index.php', body, {headers:headers}).subscribe(data => {
        this.registerResponse = data;
        this.user.set('candidateID', this.registerResponse.candidateID);
        this.user.set('candidateDetailsSubmitted', 1);        
        this.user.save();           
          this.navCtrl.setRoot(DashboardPage);
      }); 

    }         

  } 


  takeRegistrationSelfie() {

    Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        cameraDirection: 1        
    }).then((imageData) => {
    this.selfieImage = "data:image/jpeg;base64," + imageData;     
    }, (err) => {
        console.log(err);
    });    

  }

  chooseRegistrationSelfie() {

    Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        cameraDirection: 1,
        sourceType: 0,
        mediaType: 0     
    }).then((imageData) => {
        this.selfieImage = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });    

  }  

  takeRegistrationPassport() {

    Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true      
    }).then((imageData) => {
        this.passportImage = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });    

  } 

  chooseRegistrationPassport() {

    Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        sourceType: 0,
        mediaType: 0                 
    }).then((imageData) => {
        this.passportImage = "data:image/jpeg;base64," + imageData;
    }, (err) => {
        console.log(err);
    });    

  }   

  lookupButton() {

  let loading = this.loadingCtrl.create({
    spinner: 'bubbles',
    content: 'Looking up address ...',
    duration: 5000
  });

    loading.present();

    let postcode = this.lookupPostcode.replace(/\W/g, '');

  this.http.get('https://api.getAddress.io/v2/uk/'+postcode+'?api-key=KEY&format=true').map(res => res.json().Addresses).subscribe(data => {
    this.lookupAddresses = data;
    loading.dismiss();
  }); 

  } 

  setAddress(address1, address2, town) {
    this.candidateAddress1 = address1;
    this.candidateAddress2 = address2;  
    this.candidateTown = town;
    this.candidatePostcode = this.lookupPostcode;
    this.addressSelected = true;
  }

  ionViewDidLoad() {
    console.log('Hello RegisterPage Page');
  }

}

register.html

<!--
  Generated template for the Register page.

  See http://ionicframework.com/docs/v2/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar>
    <ion-title>Complete registration</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding class="login-special">

    <div *ngIf="registerStep == 0 ">

        <ion-list>
            <ion-item>
                <ion-label floating>Your first name</ion-label>
                <ion-input [(ngModel)]="candidateFirstName" type="text" value=""></ion-input>
            </ion-item>

            <ion-item>
                <ion-label floating>Your last name</ion-label>
                <ion-input [(ngModel)]="candidateLastName" type="text" value=""></ion-input>
            </ion-item>

            <ion-item>
                <ion-label floating>Your telephone number</ion-label>
                <ion-input [(ngModel)]="candidatePhone" type="tel" value=""></ion-input>
            </ion-item> 

            <ion-item>
                <ion-label floating>Your date of birth</ion-label>
                <ion-datetime displayFormat="DD/MM/YYYY" [(ngModel)]="candidateDOB"></ion-datetime>
            </ion-item> 
            <br />
            <ion-label class="gender-select-title">Choose your gender</ion-label>
            <ion-list radio-group [(ngModel)]="candidateGender" class="two-col-selector">
                <ion-item>
                    <ion-label>Male</ion-label>
                    <ion-radio value="1"></ion-radio>
                </ion-item>
                <ion-item>
                    <ion-label>Female</ion-label>
                    <ion-radio value="2"></ion-radio>
                </ion-item>

            </ion-list>                           

        </ion-list>

        <div>

          <button [disabled]="!candidateFirstName || !candidateLastName || !candidatePhone || !candidateDOB || !candidateGender" ion-button color="primary" full (click)="doRegistration(1)">
            Next step
          </button>

        </div>  

    </div>

    <div *ngIf="registerStep == 1 ">

        <ion-list>
            <ion-item *ngIf="!addressSelected" class="address-finder">
                <ion-label floating>Enter Postcode</ion-label>
                <ion-input [(ngModel)]="lookupPostcode" type="text" value=""></ion-input>
            </ion-item>
            <button *ngIf="!addressSelected" ion-button class="button find-address" (click)="lookupButton()">FIND YOUR ADDRESS</button>

            <div *ngIf="!addressSelected">

                <p *ngIf="lookupAddresses?.length > 0">Select your address from the list below</p>

                <div *ngFor="let a of lookupAddresses" class="address-list">
                    <div (click)="setAddress(a[0], a[1], a[3])" class="address-item">{{ a[0] }}</div>
                </div>          

                <a class="text-link" (click)="setAddress('', '', '')">Address not found? Click here.</a>    

            </div>  

            <div *ngIf="addressSelected">               

                <ion-item>
                    <ion-label floating>Address line 1</ion-label>
                    <ion-input [(ngModel)]="candidateAddress1" type="text" value=""></ion-input>
                </ion-item>

                <ion-item>
                    <ion-label floating>Address line 2</ion-label>
                    <ion-input [(ngModel)]="candidateAddress2" type="text" value=""></ion-input>
                </ion-item>

                <ion-item>
                    <ion-label floating>Town</ion-label>
                    <ion-input [(ngModel)]="candidateTown" type="email" value=""></ion-input>
                </ion-item> 

                <ion-item>
                    <ion-label floating>Postcode</ion-label>
                    <ion-input [(ngModel)]="candidatePostcode" type="text" value=""></ion-input>
                </ion-item>

            </div>

        </ion-list>

        <div>

          <button *ngIf="addressSelected" [disabled]="!candidateAddress1 || !candidateTown || !candidatePostcode" ion-button color="primary" full (click)="doRegistration(2)">
            Next step
          </button>

        </div>  

    </div>  

    <div *ngIf="registerStep == 2 ">

        <div *ngIf="selfieImage == null">

                <h1>Add a selfie of yourself</h1>
                <p class="body-text">We need to see a picture of you to help us verify your identity. It won't be public and only our computer will see it.</p>

                <div class="selfie-placeholder ion-ios-person"></div>

                <div class="button-container">
                    <button ion-button color="primary" full (click)="takeRegistrationSelfie()">
                        Take a selfie
                    </button>       

                    <button ion-button color="primary" full (click)="chooseRegistrationSelfie()">
                        Choose a selfie
                    </button>                       
                </div>
        </div>

        <div *ngIf="selfieImage">

            <img [src]="DomSanitizer.bypassSecurityTrustUrl(selfieImage)" class="registerImage" *ngIf="selfieImage" />

            <div class="button-container">
                <button ion-button color="light" full (click)="takeRegistrationSelfie()">
                    Take it again?
                </button>               

                <button ion-button color="light" full (click)="chooseRegistrationSelfie()">
                    Choose another?
                </button>               
            </div>
                <button ion-button color="secondary" full (click)="doRegistration(3)" class="next-step-btn">
                    Happy? Next step
                </button>
        </div>  

    </div>  

    <div *ngIf="registerStep == 3 ">

        <div *ngIf="passportImage == null">

            <h1>Add a passport photo</h1>
                <p class="body-text">We need proof that you have the right to work in the UK. A picture of your passport is enough for now.</p>

            <div class="button-container">
                <button ion-button color="primary" full (click)="takeRegistrationPassport()">
                    Take a photo
                </button>       

                <button ion-button color="primary" full (click)="chooseRegistrationPassport()">
                    Choose a photo
                </button>                       
            </div>
        </div>

        <div *ngIf="passportImage">

            <img [src]="DomSanitizer.bypassSecurityTrustUrl(passportImage)" class="registerImage" *ngIf="passportImage" />

            <div class="button-container">
                  <button ion-button color="light" full (click)="takeRegistrationPassport()">
                    Take it again?
                  </button>             

                  <button ion-button color="light" full (click)="chooseRegistrationPassport()">
                    Choose another?
                  </button>             

            </div>  
            <button ion-button color="secondary" full (click)="doRegistration(4)">
                    Happy? Next step
                  </button> 

        </div>          

    </div>

    <div *ngIf="registerStep == 4 ">

        <h3>The legal bit</h3>

        <div class="scrollable">
            <h4>Terms and Conditions</h4>
            <p>1. Lorem ipsum dolor</p>
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam feugiat mi in justo mollis faucibus. Proin eu sollicitudin nibh. Quisque blandit pulvinar nisl, vitae aliquet metus vulputate eget. Cras ac sagittis enim. Fusce mattis, ante ac tempus auctor, lacus lectus dignissim dui, eu venenatis tellus mi a ante. Proin blandit diam mauris, eu vestibulum sapien ullamcorper eget. Integer blandit a risus ut interdum. Cras neque urna, tempor ullamcorper placerat feugiat, mollis eu dolor.</p>
            <p>Proin eget consectetur ligula. Quisque fringilla eu est in rhoncus. In sollicitudin est nec ligula euismod, a euismod nulla vehicula. Vestibulum non vestibulum lorem, ac pharetra nisl. Donec erat nibh, dignissim vulputate dictum a, aliquet in leo. Maecenas facilisis sem vel est cursus, sagittis rutrum massa blandit. Vestibulum faucibus enim vel lorem auctor bibendum. Proin at mi lorem. </p>
        </div>

        <ion-item>
            <ion-label>I&rsquo;ve read and accept the Terms</ion-label>
            <ion-checkbox [(ngModel)]="acceptTerms" color="default" checked="false"></ion-checkbox>
        </ion-item>

        <ion-item>
            <ion-label>I&rsquo;ve submitted <strong>only</strong> my own ID</ion-label>
            <ion-checkbox [(ngModel)]="ownID" color="default" checked="false"></ion-checkbox>
        </ion-item>

        <button [disabled]="!acceptTerms || !ownID" margin-top ion-button color="secondary" full (click)="doRegistration(5)">
            Complete sign up
        </button>       

    </div>              

</ion-content>
1
votes

Try with ngZone to make Angular detect the change.

constructor(private _ngZone:NgZOne,....){}

//....
 Camera.getPicture({
        destinationType: Camera.DestinationType.DATA_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        cameraDirection: 1        
    }).then((imageData) => {
      // imageData is a base64 encoded string
        this._ngZone.run(()=>{
           this.selfieImage = "data:image/jpeg;base64," + imageData;
        })
    }, (err) => {
        console.log(err);
    });    

Or I had done this using FILE_URL.

Camera.getPicture({
        destinationType: Camera.DestinationType.FILE_URL,
        targetWidth: 1000,
        targetHeight: 1000,
        correctOrientation: true,
        cameraDirection: 1        
    }).then((imageURL) => {
           this.selfieImage = imageURL;
        })
    }, (err) => {
        console.log(err);
    });    
0
votes

Have you tried

<img data-ng-src="{{selfieImage}}">