[Ionic 5] [Angular] ion-select does not show the selected values

Ionic:

Ionic CLI : 6.0.0
Ionic Framework : @ionic/angular 5.0.0
@angular-devkit/build-angular : 0.801.3
@angular-devkit/schematics : 8.1.3
@angular/cli : 8.1.3
@ionic/angular-toolkit : 2.1.2

You can see on the gif below, when I try to edit the modal, nothing is selected on “Coletor”. However, after clicking on “Coletor” the “Linha 02” is already selected. It works properly with the field “Permissão” though:

screencast-localhost_8100-2020.04.05-15_43_19

config-add-user.page.html

<ion-header>

  <ion-toolbar color="primary">
    <ion-buttons slot="start">
      <ion-button (click)="closeModal()">
        <ion-icon name="arrow-back-outline"></ion-icon>
      </ion-button>
    </ion-buttons>
    <ion-title><b>Usuário</b></ion-title>
  </ion-toolbar>

</ion-header>

<ion-content class="ion-padding">

  <form [formGroup]="addUserGroup">
    <ion-list inset ion-no-border>

      <ion-item>
        <ion-label color="medium">Usuário:</ion-label>
        <ion-input class="ion-text-end" type="text" name="username" formControlName="username" value="{{ username }}"></ion-input>
      </ion-item>

      <br>

      <ion-item>
        <ion-label color="medium">Password:</ion-label>
        <ion-input class="ion-text-end" type="password" name="password" formControlName="password" value="{{ password }}"></ion-input>
      </ion-item>

      <br>

      <ion-item>
        <ion-label color="medium">Name:</ion-label>
        <ion-input class="ion-text-end" type="text" name="name" formControlName="name" value="{{ name }}"></ion-input>
      </ion-item>

      <br>

      <ion-item>
        <ion-label color="medium">Permissão:</ion-label>
        <ion-select class="ion-text-end" name="permission" formControlName="permission" value="{{ selectPermission }}">
            <ion-select-option value="1">Usuário</ion-select-option>
            <ion-select-option value="2">Administrador</ion-select-option>
        </ion-select>
        <ion-icon name="chevron-forward-outline" color="primary" item-end></ion-icon>
      </ion-item>

      <br>

      <ion-item>
        <ion-label color="medium">Coletor:</ion-label>
        <ion-select class="ion-text-end" multiple="true" name="idLine" formControlName="idLine" [(value)]="selectLine">
          <ion-select-option *ngFor="let item of linesList" value="{{item.id}}">
            {{ item.name }}
          </ion-select-option>
        </ion-select>
        <ion-icon name="chevron-forward-outline" color="primary" item-end></ion-icon>
      </ion-item>

      <br>
    
    </ion-list>

    <ion-row>
      <ion-col>
        <ion-button [disabled]="addUserGroup.invalid" (click)="postUser()" type="submit" expand="block" size="large">SALVAR</ion-button>
      </ion-col>
    </ion-row>

  </form>

</ion-content>

config-add-user.page.ts

/*****************************************************/
/******************* GENERAL IMPORTS *****************/
/*****************************************************/

import { UserService } from '../api/user.service';
import { Component, Input } from '@angular/core';
import { Validators, FormBuilder, FormControl } from '@angular/forms';
import { AlertController, ModalController } from '@ionic/angular';

@Component({
  selector: 'app-config-add-user',
  templateUrl: './config-add-user.page.html',
  styleUrls: ['./config-add-user.page.scss'],
})

export class ConfigAddUserPage {

  /* DATA VARIABLES */
  addUserGroup: any = {};
  linesList: Array<any>;

  /* EDIT VARIABLES */
  selectLine: Array<any>;
  selectPermission: string;

  // Data passed in by componentProps
  @Input() modal: any;
  @Input() edit: string;
  @Input() token: string;
  @Input() id: string;
  @Input() idLine: Array<any>;
  @Input() clientId: string;
  @Input() username: string;
  @Input() password: string;
  @Input() name: string;
  @Input() permission: string;

  constructor(
    public service : UserService,
    public alertCtrl: AlertController,
    public formBuilder : FormBuilder,
    public modalController: ModalController,
  ) {

      /*****************************************************/
      /****************** FORM VALIDATOR *******************/
      /*****************************************************/

      this.addUserGroup = this.formBuilder.group({
        token: new FormControl('xxxx', Validators.required),
        dns: new FormControl(this.service.getDns(), Validators.required),
        user: new FormControl(this.service.getUser(), Validators.required),
        pass: new FormControl(this.service.getPass(), Validators.required),
        clientId: new FormControl(this.service.getClientId(), Validators.required),
        id: new FormControl(this.id),
        username: new FormControl('', Validators.required),
        password: new FormControl('', Validators.required),
        name: new FormControl('', Validators.required),
        permission: new FormControl('', Validators.required),
        idLine: new FormControl('', Validators.required)
      });
  }

  /*****************************************************/
  /****************** ONINIT FUNCTIONS *****************/
  /*****************************************************/

  ionViewDidEnter() {
    this.getProductionLines();
    this.selectPermission = this.permission;
    this.selectLine = this.idLine;

    // Removing Ion Select Icons
    const ionChange = document.querySelectorAll('ion-select');
    ionChange.forEach((sel) => {
      sel.shadowRoot.querySelectorAll('.select-icon-inner')
        .forEach((elem) => {
          elem.setAttribute('style', 'display: none;');
        });
    });
  }

  /*****************************************************/
  /****************** POST OR UPDATE *******************/
  /*****************************************************/

  postUser() {
    if (this.edit == "true") {
      this.service.updateDataUser(this.addUserGroup.value)
        .subscribe(
          data=>{
            console.log(data.message);
        }, 
          err=>console.log(err)
      );
      this.modal.dismiss();
    } 
    if (this.edit == "false") {
      this.service.postDataUser(this.addUserGroup.value)
        .subscribe(
          data=>{
            if (data.search === false) {
              console.log(data.message);
              this.modal.dismiss();
            } else {
              console.log(data.message);
              this.postAlert();
            }
        },
          err=>console.log(err)
      );
      this.modal.dismiss();
    }
  }

  async postAlert() {
    const alert = await this.alertCtrl.create({
      header: 'Usuário Repetido',
      message: 'Tente outro username...',
      buttons: ['OK']
    });
    await alert.present();
  }

  /******************************************************/
  /******************* API - GET DATA *******************/
  /******************************************************/

  getProductionLines() {
    this.service.getDataProductionLines().subscribe(
      data => this.linesList = data,
      err => console.log(err)
    );
  }

  /******************************************************/
  /******************** CLOSE MODAL ********************/
  /******************************************************/

  closeModal() {
    this.modal.dismiss({
      'edit' : "",
      'token' : "", 
      'id' : "", 
      'idLine' : "", 
      'clientId' : "", 
      'username' : "", 
      'password' : "",
      'name' : "" ,
      'permission' : "",
    });
  }

}

Any ideas? :slight_smile:

My idea is “don’t mix binding methods for form controls”. If you have formControlName, get rid of all value bindings. Having more than one source of truth for the form control causes infighting.

Hello, @rapropos! Thank you!

I tried to this approach and unfortunately it did not work. Actually it stopped showing the values after clicking as well.

      <ion-item>
        <ion-label color="medium">Coletor:</ion-label>
        <ion-select class="ion-text-end" multiple="true" name="idLine" formControlName="idLine">
          <ion-select-option *ngFor="let item of linesList" value="{{item.id}}">
            {{ item.name }}
          </ion-select-option>
        </ion-select>
        <ion-icon name="chevron-forward-outline" color="primary" item-end></ion-icon>
      </ion-item>

I think the problem is somehow related to the <*ngFor=“let item of linesList”>, because “selectLine” is returning the right values.

Any other ideas? I have been trying different possibiliteis for days already, hehe!

Thank you!

See if the following code behaves as you are hoping. If it doesn’t, then there’s something different between our environments or I’m misunderstanding your problem. If it does, then see if you can isolate what’s different between it and your problematic code.

interface Fruit {
  id: string;
  name: string;
}

export class HomePage {
  idLine = new FormControl();
  linesList: Fruit[] = [];

  constructor(private loaders: LoadingController) {
  }

  simulateBackend(): Observable<Fruit[]> {
    return timer(3000).pipe(map(() => [
      {id: "a", name: "apple"},
      {id: "b", name: "banana"},
      {id: "c", name: "cherry"},
    ]));
  }

  fill(): void {
    this.loaders.create().then(loader => loader.present());
    this.simulateBackend().pipe(
      finalize(() => this.loaders.dismiss()))
      .subscribe(fruits => this.linesList = fruits);
  }
}
<ion-content>
  <ion-item>
    <ion-label color="medium">Coletor:</ion-label>
    <ion-select class="ion-text-end" multiple="true" name="idLine" [formControl]="idLine">
      <ion-select-option *ngFor="let item of linesList" value="{{item.id}}">
        {{ item.name }}
      </ion-select-option>
    </ion-select>
    <ion-icon name="chevron-forward-outline" color="primary" item-end></ion-icon>
  </ion-item>
  <ion-item button (click)="fill()"><ion-label>fill</ion-label></ion-item>
</ion-content>

Thank you! I am trying to isolate what’s different!

In the meanwhile I made a test with the following code (getting rid of the ngFor) and it worked properly:

      <ion-item>
        <ion-label color="medium">Coletor:</ion-label>
        <ion-select class="ion-text-end" multiple="true" name="idLine" formControlName="idLine" [value]="selectLine">
          <ion-select-option value="1">Teste 1</ion-select-option>
          <ion-select-option value="2">Teste 2</ion-select-option>
          <ion-select-option value="3">Teste 3</ion-select-option>
        </ion-select>
        <ion-icon name="chevron-forward-outline" color="primary" item-end></ion-icon>
      </ion-item>

In order to clarify my issue I made the gif below You can see that after clicking on “Coletor” the “Linha 02” is already selected although it wasn’t being showed before. It works properly with the field “Permissão” though.

screencast-localhost_8100-2020.04.05-15_43_19

Anyway, I will use what you shared to keep investigating. If you have any ideas I do appreciate! :slight_smile:

Thank you!

1 Like

Hello, @rapropos! Thank you again for your support. Unfortunately I didn’t manage to find the solution yet :frowning:

Hello, @All!

Does anyone have an idea about how to fix it? I have searched everywhere, hehe! :pray:

I have added more information on the first topic.

Thank you! :slight_smile:

hello i faced the same problem , i used a SetTimout function to resolve it

 setTimeout(() => {
        this.form.setValue({
          profile_name: this.profile_name,
          profile_surname: this.profile_surname,
          branch_id: ["" + this.branch_id + ""]
        });

      }, 500);
1 Like

Still doesn’t work for me. Any other ideas? When data comes from the server the formcontrol value does not show correctly until you click on the select control as the original issue described.

ran through similar issue as you all.
I noticed that the value get display after clicking on the ion-select, even if you don’t select a new value.

So I tried to dirty the form but still no success.

My solution was to use [ selectedText]="form.get('wantedField').value"

Hello kaiovm,
I hope you already fixed your issue :slight_smile:
if not or for any other guy, I also ran into this “error” and in my special case, there was a “race condition” between loading server data in ngOnInit and setting the ion-select [(ngModel)] in ionViewDidEnter.
I had to ensure, that server data is loaded before ngModel is set.

While it may not be the correct way to do it, I use ngIf on the ion-select element to check if the array is null. I was experiencing the same issue as you.

Why not just initialize the backing array to []? I highly recommend adding the following to the compilerOptions stanza of tsconfig.json:

"noImplicitAny": true,
"strictNullChecks": true,
"strictPropertyInitialization": true

This way, the build process yells at me when I do this:

blowUpTheTemplate: Thingy[];

…reminding me to:

noLongerExplosive: Thingy[] = [];