Ion-input not updated until focused


#1

I have a form connected to models with NgModel as follows:

<form #orderForm="ngForm" (ngSubmit)="onSubmit(orderForm)">

<ion-list class="contact_view">
  
  <ion-item>
      <ion-label stacked>{{ 'ADDRESS_LINE_1' | translate }}</ion-label>
      <ion-input type="text" required placeholder="{{ 'ADDRESS_LINE_1_PLACEHOLDER' | translate }}" clearInput="true" name="addressLineOne" [(ngModel)]="order.addressLineOne"></ion-input>
  </ion-item>

  <ion-item>
      <ion-label stacked>{{ 'ADDRESS_LINE_2' | translate }}</ion-label>
      <ion-input type="text" placeholder="{{ 'ADDRESS_LINE_2_PLACEHOLDER' | translate }}" clearInput="true" name="addressLineTwo" [(ngModel)]="order.addressLineTwo"></ion-input>
  </ion-item>

This has been working well for me when I was using it as one direction binding from the view to the model.

Now, I want to be able to update the input value from the code, as follows:

ionViewDidEnter() {
    // attempt to load order from memory
    this.storageService
    .get<Order>(StorageKeys.ShippingDetails)
    .then(order => {
        // if order was loaded
        if (order) {
            // test
            this.order.addressLineOne = "aaaa"; // test
            // update UI components
            //this.changeDetectorRef.markForCheck(); // not working
            
            //this.changeDetectorRef.detectChanges(); // not working
            // run inside ngZone to update UI
            
            //this.ngZone.run(() => {
                    // init order from memory
                    //this.order.addressLineOne = "bbbb"; // not working
            //    });
        }
    });
}

The AddressLineOne is only updated when one of the inputs is focused.

I tried changeDetectorRef.markForCheck(),detectChanges() and running inside ngZone but it doesn’t work.

Can someone point me in the right direction?


#2

Use your code in "ionViewDidEnter()"
In constructor, not ion “ionViewDidEnter()”


#4

still doesn’t update unless I focus on some input


#5

add you full component code please


#6
import { NgForm } from '@angular/forms/src/directives';
import { Component, ChangeDetectionStrategy, NgZone } from '@angular/core';
import { LoadingController, NavController, ViewController, NavParams } from 'ionic-angular';
import { Observable } from 'rxjs/rx';
import { TrackPage } from '../pages';
import { TrackingIdentifier, TrackingIdentifierType, Order } from '../../models/models';
import { ApiService, LoadingService, StorageService, StorageKeys, IAppState } from '../../shared/shared';
import { BidActions } from '../../actions/actions';
import { Store } from '@ngrx/store'; 
import { GoogleAnalytics } from '@ionic-native/google-analytics';

// import { FormBuilder, FormGroup, Validator, Validators } from '@angular/forms';
import { TranslateService } from 'ng2-translate';

@Component({
    selector: 'page-OrderPage',
    templateUrl: 'OrderPage.html',
})
export class OrderPage {
    // private orderForm: FormGroup;
    private bidId: number;
    private order: Order;

    constructor(
      public navCtrl: NavController,
      public navParams: NavParams,
      public viewCtrl: ViewController,
      public ApiService: ApiService,
      public loadingService: LoadingService,
      public storageService: StorageService,
      private translate: TranslateService,
      private ngZone: NgZone,
      private store: Store<IAppState>,
      private bidActions: BidActions,
      private analytics: GoogleAnalytics) {
      // private formBuilder: FormBuilder
        
        // extract bid id
        this.bidId = this.navParams.data as number;
        
        // init default order
        this.order = new Order(this.bidId);

        this.storageService
        .get<Order>(StorageKeys.ShippingDetails)
        .then(order => {
            // if order was loaded
            if (order) {
                // run inside ngZone to update UI
                this.ngZone.run(() => {
                    // init order from memory
                    this.order.addressLineOne = "aaaa";
                    //this.order = new Order(this.bidId, order);
                });

                //this.order.addressLineOne = "aaaa";
            }
        });
    }


    ionViewDidLoad() {
        // track page in analytics
        this.analytics.trackView("Order Page");
    }

    ionViewDidEnter() {
        // attempt to load order from memory
        // this.storageService
        //     .get<Order>(StorageKeys.ShippingDetails)
        //     .then(order => {
        //         // if order was loaded
        //         if (order) {
        //             // run inside ngZone to update UI
        //             this.ngZone.run(() => {
        //                 // init order from memory
        //                 this.order = new Order(this.bidId, order);
        //             });

        //             //this.order.addressLineOne = "aaaa";
        //         }
        //     });
    }

    onSubmit(form: NgForm){
      // place order
      this.placeOrder();
    }

    placeOrder() {
        // show loading
        this.loadingService.present();
        // track
        this.analytics.trackEvent('Bid', 'Ordered');
        // place order
        this.ApiService.placeOrder(this.order)
                       .subscribe(data => {
                            // extract transaction id from response
                            let transactionid = data.order.transactionId;
                            // extract update bid from response
                            let bid = data.order.bid;
                            // update bid in data store
                            this.store.dispatch(this.bidActions.updateStatus(bid));
                            // go to tracking page
                            this.track(transactionid);
                        }, err => {
                            // dismiss loader
                            this.loadingService.dismiss();
                            // TODO: show error message to user
                        });

        // save shipping details for future orders
        this.storageService.set(StorageKeys.ShippingDetails, this.order);
    }

    track(transactionId: number) {
        // pop this page from the navigation stack
        this.navCtrl.pop();
        // go to order page
        this.navCtrl.push(
          TrackPage,
          new TrackingIdentifier(transactionId, TrackingIdentifierType.Transaction)
        );
    }
}


#7

you don’t need NgZone for updating UI
using [(NgModel)] set to 2 way bindings

Try this code in your constructor:

constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public viewCtrl: ViewController,
    public ApiService: ApiService,
    public loadingService: LoadingService,
    public storageService: StorageService,
    private translate: TranslateService,
    private ngZone: NgZone,
    private store: Store<IAppState>,
    private bidActions: BidActions,
    private analytics: GoogleAnalytics) {
    let self = this;
    // private formBuilder: FormBuilder

    // extract bid id
    this.bidId = this.navParams.data as number;

    // init default order
    this.order = new Order(this.bidId);

    this.storageService
      .get<Order>(StorageKeys.ShippingDetails)
      .then(order => {
        // if order was loaded
        if (order) {
          self.order.addressLineOne = "Order Loaded";
        } else {
          self.order.addressLineOne = "Order Not Loaded";
        }
      });
  }```

#8

Thanks for the reply. as you can see in the original post, I do use

[(ngModel)]="order.addressLineOne"

for two way binding but it still doesn’t update.

Not sure what self is but I can’t seem to use it. I get the following error:

Property ‘order’ does not exist on type ‘Window’.


#9

self is reference if this.

try this code:

constructor(
    public navCtrl: NavController,
    public navParams: NavParams,
    public viewCtrl: ViewController,
    public ApiService: ApiService,
    public loadingService: LoadingService,
    public storageService: StorageService,
    private translate: TranslateService,
    private ngZone: NgZone,
    private store: Store<IAppState>,
    private bidActions: BidActions,
    private analytics: GoogleAnalytics) {

    // private formBuilder: FormBuilder

    // extract bid id
    this.bidId = this.navParams.data as number;

    // init default order
    this.order = new Order(this.bidId);
    let self = this;
    this.storageService
      .get<Order>(StorageKeys.ShippingDetails)
      .then(order => {
        // if order was loaded
        if (order) {
          self.order.addressLineOne = "Order Loaded";
        } else {
          self.order.addressLineOne = "Order Not Loaded";
        }
      });
  }

#10

remove private from this


#11

If all this not helped remove the block

this.storageService
      .get<Order>(StorageKeys.ShippingDetails)
      .then(order => {
        // if order was loaded
        if (order) {
          self.order.addressLineOne = "Order Loaded";
        } else {
          self.order.addressLineOne = "Order Not Loaded";
        }
      });

and write only

this.order.addressLineOne = "Test";

#12

none of the above worked … maybe this is an issue with ionic?


#13

No i use form without any problem.
I suggest for you to use FormBuilder Docs


#14

Hi, sorry for the simple answer, but does this occur when you do ionic run, and ionic build ?

Some css classes doesn’t work in dev mode.

François


#15

UPDATE

    // THIS LINE WORKS
    this.order.addressLineOne = "aaba";

     this.storageService
         .get<Order>(StorageKeys.ShippingDetails)
         .then(order => {
            // if order was loaded
            if (order) {
                // THIS LINE DOESN"T WORK
                this.order.addressLineTwo = "aaaa";
                // update UI components
                this.changeDetectorRef.markForCheck();
            }
        });

When the model is updated from an async callback it doesn’t work