Push to array from promise


#1

I’m trying to build an app that involves scanning a qr-code and process the data.

My Info:
Your system information:

ordova CLI: 6.4.0
Ionic Framework Version: 2.0.0-rc.5
Ionic CLI Version: 2.1.18
Ionic App Lib Version: 2.1.9
Ionic App Scripts Version: 1.0.0
ios-deploy version: Not installed
ios-sim version: Not installed
OS: Windows 10
Node Version: v6.9.1
Xcode version: Not installed

This is a small working example:

ionic start qrscan-sample tabs --v2
cd qrscan-sample
ionic platform add android
ionic plugin add phonegap-plugin-barcodescanner
npm install

Change home.html to:

<ion-content padding>
  <ion-card *ngFor="let item of items">
    {{item}}
  </ion-card>

  <ion-fab center bottom>
    <button ion-fab color="light" (click)="scan()"><ion-icon name="qr-scanner"></ion-icon></button>
  </ion-fab>
</ion-content>

Change home.ts to:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';

import { BarcodeScanner } from 'ionic-native';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public plat: Platform) {
  }

  public items: string[] = [];

  scan() {
    this.plat.ready().then(() => {
      BarcodeScanner.scan().then((barcodeData) => {
        // success
        this.items.push(barcodeData.text);
      }, (err) => {
        // error
        alert(err);
      });
    });
  }

}

It works as expected, when the code is all in one place.

But when I want to extract the BarcodeScanner-Part into a provider…

ionic g provider barcode-scanner-service

barcode-scanner-service.ts:

import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { BarcodeScanner } from 'ionic-native';

@Injectable()
export class BarcodeScannerService {

  constructor(public plat: Platform) {
  }

  scan(): Promise<string> {
    return this.plat.ready().then(() => {
      return BarcodeScanner.scan()
        .then((barcodeData) => {
          // success
          return barcodeData.text;
        }, (err) => {
          // error
          alert(err);
        });
    });
  }

}

home.ts:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';

import { BarcodeScanner } from 'ionic-native';

import { BarcodeScannerService } from '../../providers/barcode-scanner-service';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {

  constructor(public plat: Platform, public barcodeScannerService: BarcodeScannerService) {
  }

  public items: string[] = [];

  scan() {
    let x = this.barcodeScannerService.scan()
      .then(function (result) {
        this.contacts.push(result);
      }).catch(error => {
        alert(error);
      });
  }

}

app.module.ts:

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { BarcodeScannerService } from '../providers/barcode-scanner-service';

@NgModule({
  declarations: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    AboutPage,
    ContactPage,
    HomePage,
    TabsPage
  ],
  providers: [{ provide: ErrorHandler, useClass: IonicErrorHandler }, BarcodeScannerService]
})
export class AppModule { }

The error I get is: TypeError: Cannot read property ‘items’ of null

I have tried a lot of ways, there is something that I am missing or don’t understand.


#2

I suspect you’re being bit by a wonky execution context in your component’s scan() method. I would do it this way:

this.barcodeScannerService.scan().then((qr) => {
  this.items.push(qr);
});

The use of a fat arrow function will ensure this is correct.


#3

Thanks a bunch, it works and the explanation makes sense :slight_smile: