angularselectngmodelangularjs-ng-value

Can't make select work properly with ngmodel


I have a "lookup" select which needs to work as a "passive" control: highlight the selected option and as an "active" control: let user select the option and initiate some action (load corresponding entity's details). I tried a lot and can't make it work properly:

            <select
              class="browser-default custom-select"
              (ngModelChange)="onEdit($event)" [(ngModel)]="selected.id" [ngModelOptions]="{standalone: true}">
              <option [ngValue]="null">{{ '::Licences:SelectLicence' | abpLocalization }}</option>
              <ng-container *ngIf="licencesLookupData$ | async">
                <option
                  *ngFor="let l of licencesLookupData$ | async"
                  [ngValue]="l.id"
                  [selected]="l.id === selected.id"
                >
                  {{ l.id }} &nbsp;&nbsp; {{ l.displayName | defaultValue }}
                </option>
              </ng-container>
            </select>

At first, I have tried to avoid ngModel, but then I had the problem with id - it is an integer, but was treated as a string. Now the types are correct (numbers), but the selected option is never selected, even though the correct data is loaded and selected.id gets a number value.

Lookup is an ordinary observable with numeric id key:

  licencesLookupData$: Observable<Common.Lookup<number>[]>;

  export interface Lookup<T> {
      id: T;
      displayName: string;
  }

onEdit method:

  onEdit(id?: number) {
    if (id === null) {
      this.onAdd();
      return;
    }
    this.licencesLoading = true;
    this.licencesService
      .getById(id)
      .pipe(finalize(() => (this.licencesLoading = false)), takeUntil(this.destroy))
      .subscribe((state: Licences.LicenceWithFlatProperties) => {
        this.selected = state;
        this.buildForm();
        this.get();
      });
  }

Solution

  • After many trials, this is what finally worked for me:

      <select
        class="browser-default custom-select"
        (change)="onEdit($event.target.value)"
      >
        <option [value]="">{{
          '::Licences:SelectLicence' | abpLocalization
        }}</option>
        <ng-container *ngIf="licencesLookupData$ | async">
          <option
            *ngFor="let l of licencesLookupData$ | async"
            [ngValue]="l.id"
            [value]="l.id"
            [selected]="l.id == selected.id"
          >
            {{ l.id }} &nbsp;&nbsp; {{ l.displayName | defaultValue }}
          </option>
        </ng-container>
      </select>
    
      onEdit(idString: string) {
        const id = Number(idString);
        if (isNaN(id)) {
          this.onAdd();
          return;
        }
        this.licencesLoading = true;
        this.licencesService
          .getById(id)
          .pipe(finalize(() => (this.licencesLoading = false)), takeUntil(this.destroy))
          .subscribe((state: Licences.LicenceWithFlatProperties) => {
            this.selected = state;
            this.buildForm();
            this.get();
          });
      }