Ion-input not updated until focused

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?

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

still doesn’t update unless I focus on some input

add you full component code please

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)
        );
    }
}

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";
        }
      });
  }```

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’.

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";
        }
      });
  }

remove private from this

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";

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

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

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

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