Loading data from localbrowser DB to ion-select isn't working

Hello all.
I’ve just about given up on how to make this work. I don’t know what else to do now except ask for help as I’ve been working on this for days.

I’m using ionic-v4.

What I’m trying to do is have a settings page be able to load and save values. I plan on storing this in local storage, and numeral values and other pages in my app are working where I’m just using a standard INPUT tag, however using an ion-select, it doesn’t work at all. All I seem to get is error messages - if a value in the local browser db exists. If a value in the dB doesn’t exist, it’ll move to the next ion-select, and they show an error.

I know this error is common to many people as I’ve been researching this and open a hundred links, but it’s rather complicated.

This is the frustrating error I get:

ERROR Error: “ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘model: fueltype’. Current value: ‘model: LPG’.”
Angular 7
View_SettingsPage_1 SettingsPage.html:32
Angular 27
RxJS 5
Angular 11
ERROR CONTEXTObject { view: {…}, nodeIndex: 36, nodeDef: {…}, elDef: {…}, elView: {…} }

My HTML code (with a shorten list of options) is:

<ion-header>
    <ion-toolbar>
        <ion-buttons slot="start">
          <ion-menu-button></ion-menu-button>
        </ion-buttons>
        <ion-title>
          Settings
        </ion-title>
      </ion-toolbar>
</ion-header>

<ion-content *ngIf="displayMain">
    <ion-card class="welcome-card"> 
        <ion-card-header>
          <ion-card-subtitle>Settings</ion-card-subtitle>
          <ion-card-title>Adjust as required.</ion-card-title>
        </ion-card-header>
        <ion-card-content>
          <p>Make the changes required for the default settings of the app.</p>
        </ion-card-content>
      </ion-card>
       
      <ion-grid padding>
          <ion-row>
              <ion-col col-12>   
                <ion-list>
                    <ion-label>App Settings</ion-label>
                    <ion-item>
                      <ion-label>Fuel Type</ion-label>
                      <br>
                      <ion-select  name="fueltype" id="fueltype" [(ngModel)]="fueltype"  value="{{fueltypeVal}}" okText="Save" cancelText="Cancel"> 
                        <ion-select-option value="91Petrol">91 Petrol</ion-select-option>
                        <ion-select-option value="LPG">LPG</ion-select-option>
                        <ion-select-option value="Gasoline">Gasoline</ion-select-option>
                        <ion-select-option value="Diesel">Diesel</ion-select-option> 
                      </ion-select>
                    </ion-item> 
                  </ion-list> 
              </ion-col>
          </ion-row> 

          <ion-row>
            <ion-col col-12>
                <ion-list>
                  <ion-label>Amount of Fuel </ion-label>
                  <br>
                  <ion-input class="pricenumbers" id="fuelamount" [(ngModel)]="fuelamount" type="number"></ion-input>
                </ion-list>
              </ion-col>
          </ion-row>

          <ion-row>
              <ion-col col-12>
                  <ion-list>
                    <ion-label>Country </ion-label>
                    <br>
                    <ion-select  name="country" id="country" [(ngModel)]="country"  value="{{countryVal}}" okText="Save" cancelText="Cancel">  
                        <ion-select-option value="cents">Cents</ion-select-option>
                        <ion-select-option value="dollars">Dollars</ion-select-option>
                      </ion-select>
                  </ion-list>
                </ion-col>
            </ion-row>

            <ion-row>
                <ion-col col-12>
                    <ion-list>
                      <ion-label>Measurement</ion-label>
                      <br>
                      <ion-select  name="measurement" id="measurement" [(ngModel)]="measurement"  value="{{measurementVal}}" okText="Save" cancelText="Cancel"> 
                          <ion-select-option value="litres">Litres</ion-select-option>
                          <ion-select-option value="gallons">Gallons</ion-select-option>
                        </ion-select>
                    </ion-list>
                  </ion-col>
              </ion-row>
 
            <ion-row>
                <ion-col col-12>
                    <button ion-button (click) = "saveSettings()" icon-start large round color="dark" style="width:100%; font-size: 3em;">
                        <ion-icon name="star" hidden></ion-icon>
                        Save settings
                    </button> 

                    <button hidden ion-button (click) = "loadSettings()" icon-start large round color="dark" style="width:100%; font-size: 3em;">
                      <ion-icon name="star" hidden></ion-icon>
                      Load settings
                  </button> 
                </ion-col>
            </ion-row> 
          
      </ion-grid> 
</ion-content>

My TS code is:


import { Component, OnInit } from '@angular/core';
import { Storage } from '@ionic/storage';  


@Component({
  selector: 'app-settings',
  templateUrl: './settings.page.html',
  styleUrls: ['./settings.page.scss'],
})
export class SettingsPage implements OnInit {
  

  constructor(private storage: Storage 
    ) { }

  fueltype: any = "fueltype";
  fueltypeVal: any = "Litres";
  fueltemp: any;
  displayMain: boolean;
  countryVal: any  = 0;
  measurementVal: any = 0;
  country: any = 0;
  measurement: any; 
  fuelamount: number = 50;
 

 ionViewWillEnter ()
 { 
  this.displayMain = false; 
  setTimeout(() => { 
    this.getSettings(); 
  },0);  
  this.displayMain = true;
 }

 ngOnInit()
  {    
  }  

  async getSettings()
  {
      // set a key/value   
        this.storage.get('fueltype').then((val) => { 
        this.fueltypeVal = val; 
 
        console.debug (this.fueltypeVal); 
      });  

        this.storage.get('fuel').then((val) => { 
        this.fuelamount = val;
        console.debug (this.fuelamount);
      });  

        this.storage.get('country').then((val) => { 
        this.countryVal = val; 
        console.debug (this.countryVal); 
      });  

       this.storage.get('measurement').then((val) => { 
        this.measurementVal = val;
        console.debug (this.measurementVal);
      });  

      console.debug (this.fueltype);
      console.debug (this.fuelamount);
      console.debug (this.country);
      console.debug (this.measurement); 
      console.debug (this.fueltypeVal);
      console.debug (this.fuelamount);
      console.debug (this.countryVal);
      console.debug (this.measurementVal);  

  }

  saveSettings()
  {
    this.storage.set('fueltype', this.fueltype);
    this.storage.set('fuel', this.fuelamount);   
    this.storage.set('country', this.country);
    this.storage.set('measurement', this.measurement);  
    console.debug (this.fueltype);
    console.debug (this.fuelamount);
    console.debug (this.country);
    console.debug (this.measurement); 
    console.debug (this.fueltypeVal);
    console.debug (this.fuelamount);
    console.debug (this.countryVal);
    console.debug (this.measurementVal); 
  }

  loadSettings()
  {
    this.getSettings();
  }

}

I don’t think I’m doing anything strange, because it works fine on the standard “Input” Tag. Just not these select options. Any thoughts? Am I approaching this in the wrong way?
Thanks in advance.
-Steve

Things I would do differently:

  • replace every any with a real type
  • move all interaction with Storage out of this page and into a service
  • declare return types for all functions
  • get rid of the setTimeout
  • either lose the async on getSettings or make it actually return a Promise that resolves when it’s done (using Promise.all, for example)
  • consider putting all of these things into a single object, so that you are only hitting Storage once to fetch/save them all
  • use reactive forms

Finally, and most germane to your most immediate problem, see this thread. You have two sets of competing/conflicting sources of truth in several places, such as fueltype and fueltypeVal. I would lose the ones ending in Val and the value attributes that reference them.

Thanks, I’ll have a good look at your suggestions and refactor everything. Some of those things I’d put in there, such as the dual variables and the setTimeout were from other examples I’d seen and tried to make a mish-mash to something that would work. I’ll take a good look at reactive forms. They look rather interesting.
And, as much as it pains me to do it, I think I’ll have to go and store the values in an array as suggested. It’s probably my old-school thinking that’s got me doing things that way.
I’ll let you know how I go. Cheers.

Thanks for your help. In an effort to fix the weird error message, I did some cleanup of the code, but the biggest thing that solved that initial message was the multiple points of truth you mentioned. That was the thing that was killing everything. All good now. Thanks.