Search code examples
angulartypescript

angular 18 select default value not selected


I am new to angular 18 version and want to select an initial value in html element select from a variable which is a signal. My code is as follows:

country.component.html:

<main>
    <select name="countries" id="countries-selection" >
        @for (country of countries$ | async; track country.id) {
            <option [value]="country.id" [selected]="selectedCountryId()">{{ country.name }}</option>
        }
    </select>
</main>

country.component.ts:

import { HttpClient } from '@angular/common/http';
import { Component, signal } from '@angular/core';
import { Country, CountryResponse } from './country.model';
import { Observable, map } from 'rxjs';
import { CommonModule } from '@angular/common';


@Component({
  selector: 'app-country',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './country.component.html',
  styleUrl: './country.component.css'
})
export class CountryComponent {

  countryResponse$: Observable<CountryResponse>;
  countries$: Observable<Country[]>;
  selectedCountryId = signal(5);

  constructor(private httpClient: HttpClient) {
      this.countryResponse$ = this.httpClient.get<CountryResponse>('http://localhost:3000/country');
      this.countries$ = this.countryResponse$.pipe(
        map((response: any) => {
          return response.countryList
        })
      );
  }
}

country.model.ts:

export interface Country {
    id: number;
    name: string;
    timezone: string;
}

export interface CountryResponse {
    countryList: Country;
}

Issue: an initial value is not selected for the html element select


Solution

  • Try using [(ngModel)] instead, this can be used in combination with either a signal or a model (preferred).

    Docs for using template driven forms

    HTML

    <main>
        <select name="countries" id="countries-selection" [(ngModel)]="selected"> <!-- changed here! -->
            @for (country of countries$ | async; track country.id) {
                <option [value]="country.id">{{ country.name }}</option>
            }
        </select>
    </main>
    

    TS:

    import { HttpClient } from '@angular/common/http';
    import { Component, signal } from '@angular/core';
    import { Country, CountryResponse } from './country.model';
    import { Observable, map } from 'rxjs';
    import { CommonModule } from '@angular/common';
    import { FormsModule } from '@angular/forms'; // <- changed here!
    
    
    @Component({
      selector: 'app-country',
      standalone: true,
      imports: [CommonModule, FormsModule], // <- changed here!
      templateUrl: './country.component.html',
      styleUrl: './country.component.css'
    })
    export class CountryComponent {
    
      countryResponse$: Observable<CountryResponse>;
      countries$: Observable<Country[]>;
      selected = signal(5);
    
      constructor(private httpClient: HttpClient) {
          this.countryResponse$ = this.httpClient.get<CountryResponse>('http://localhost:3000/country');
          this.countries$ = this.countryResponse$.pipe(
            map((response: any) => {
              return response.countryList
            })
          );
      }
    }