[(ngModel)] not working as expected

Though this is not related to ionic but thought of posting it here, if anyone know solution do help.

Here is what my problem case is:

I scan a barcode and navigate to next page where I ask user to input a number where I have put some checks.

Here is injectable for my scanner service, when ever I scan with scanner it is calling scannerSuccessCallback function. In that function I am broadcasting what ever I data I am getting from scanner using EventService whose code also I have posted after ScannerService::

import { Injectable } from '@angular/core';
import { EventService } from './services';
import { Platform } from 'ionic-angular';
declare var scanner: any;

@Injectable()
export class ScannerService {
    constructor(private platform: Platform,
                private eventService: EventService) {
    }
    scannerSuccessCallback = (data) => {
        this.eventService.broadcast(data.text);
    }

    scannerFailureCallback = () => {
        console.log('Scanner initialization failed...');
    }

    initializeScanner() {
        console.log('Initializing scanner...');
        if (typeof scanner !== "undefined" && typeof scanner.perform !== "undefined") {
            scanner.perform(this.scannerSuccessCallback, this.scannerFailureCallback, "setup");
        }
        else {
            console.log('Scanner already initialized!!!');
        }
    }
}

Here is EventService::

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';

type MessageCallback = (payload: any) => void;

@Injectable()
export class EventService {
    private scannedItem = new Subject<string>();

    broadcast(message: string) {
        this.scannedItem.next(message);
    }

    subscribe(callback: MessageCallback): Subscription {
        return this.scannedItem.subscribe(callback);
    }
}

I have subscribed to EventService using subscribe method in my HomePage component as::

import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Subscription } from "rxjs/Subscription";
import { EventService } from '../../services/services';
import { NextPage } from '../pages;

@Component({
  selector: 'page-scan-page',
  templateUrl: 'scan-page.html',
})
export class ScanPage {
  private scanSubscription: Subscription;
  inputBarcode: number;

  constructor(public navCtrl: NavController
    private eventService: EventService) {
  }

  ionViewWillLoad(): void {
    this.subscribeScans();
  }

  goToNextPage(){
        this.navCtrl.push(NextPage, this.inputBarcode)
  }

  subscribeScans = (): void => {
    this.scanSubscription = this.eventService.subscribe((payload) => {
      if (payload != undefined) {
        this.inputBarcode = Number(payload);
        this.goToNextPage();
      }
    });
  }
}

In next page I have input in HTML as::

<ion-input text-center type="number"
        [(ngModel)]="quantityEntered" (keydown.Tab)="updateQuantity()" (input)="verifyInput()"></ion-input>

and verifyInput is suppose to keep it in constrain from 1 to some max value, function is as::

verifyInput() {
    this.ngZone.run(() => {
      this.quantityEntered = Number((this.quantityEntered + " ").replace(/[^0-9]+/g, ""));
      if (this.quantityEntered > this.maxValue) {
        this.quantityEntered = this.maxValue;
      } else if (this.quantityEntered == 0) {
        this.quantityEntered = null;
      }
    })
    this.changeDetectorRef.detectChanges();
  }

here are screenshot of input and quantityEntered binded in HTML using {{}}

Screen Shot 2017-06-14 at 4.15.01 PM.png

So at component level quantityEntered is getting updated as per verifyInput function but it is not getting reflected in input feild.

Can anyone help.

I am initializing my scanner in app.component which is::

import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { ScanPage } from '../pages/pages';
import { ScannerService, NetworkService, SettingsService, AuthService } from '../services/services';

@Component({
  templateUrl: 'app.html'
})
export class App {
  @ViewChild(Nav) nav: Nav;

  rootPage: any = HomePage;

  constructor(public platform: Platform,
    public statusBar: StatusBar,
    public splashScreen: SplashScreen,
    public scannerService: ScannerService) {
    this.initializeApp();
  }

  initializeApp() {
    this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
          this.setupApp();
          this.statusBar.styleDefault();
          this.splashScreen.hide();
    });
  }

  setupApp() {
      this.scannerService.initializeScanner();
  }
}

and here is my app.module

import { BrowserModule } from '@angular/platform-browser';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { HttpModule } from '@angular/http';
import { FormsModule } from '@angular/forms';

import { App } from './app.component';
import { HomePage, NextPage } from '../pages/pages';
import { EventService, ScannerService} from '../services/services';

import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

@NgModule({
  declarations: [
    App,
    HomePage,
    NextPage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(App),
    HttpModule,
    FormsModule
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    App,
    HomePage,
    NextPage,
  ],
  providers: [
    StatusBar,
    Keyboard,
    SplashScreen,
    Network,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    EventService,
    ScannerService
  ]
})
export class AppModule {}

You should not need to be messing with zones or change detection. The following seems to do what you want:

<ion-input [ngModel]="quantity" (ngModelChange)="onQuantityChange($event)"></ion-input>

quantity: string;
maxValue = Number(100);

onQuantityChange(q: string): void {
  let qnum = Number.parseInt(q);
  if (qnum > this.maxValue) {
    this.quantity = this.maxValue.toString();
  } else if (qnum <= 0) {
    this.quantity = null;
  } else {
    this.quantity = qnum.toString();
  }
}
1 Like

I tried this also. But if I don’t use NgZone, this method is not even called.

Btw I figured it out. My ScannerService was in different zone than my page component. So I enclose by broadcast in this.ngZone.run and I am no longer seeing the issue.

Thanks :slight_smile:

Frankly, I would not consider that a solution. App code should not have to concern itself with zones.

thank you for replay,actually my input field ids integer type,in my scenario we are strictly avoid decimal values for that i am trying to handle with key code is wasn’t worked fine in my app,and i am trying to do with disabling dot key from numeric keypad