>>
Решение с использованием ngModel и события (change)
В Angular для работы с выпадающим списком <select> лучше всего использовать двустороннюю привязку данных через [(ngModel)] в сочетании с событием (ngModelChange). Этот подход является современным, типобезопасным и не требует ручного обращения к DOM.
Пошаговая реализация:
- Импортируйте FormsModule в ваш модуль (app.module.ts), чтобы работала директива ngModel.
- Добавьте [(ngModel)] к элементу
<select> и привяжите его к свойству компонента.
- Используйте (ngModelChange) для вызова метода при каждом изменении выбора.
Пример кода:
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms'; // <-- обязательно импортировать
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule, FormsModule],
bootstrap: [AppComponent]
})
export class AppModule { }
// my-select.component.ts
import { Component } from '@angular/core';
interface City {
id: number;
name: string;
}
@Component({
selector: 'app-my-select',
template: `
<select [(ngModel)]="selectedCityId" (ngModelChange)="onCityChange($event)">
<option *ngFor="let city of cities" [ngValue]="city.id">
{{ city.name }}
</option>
</select>
<p>Вы выбрали: {{ selectedCityName }}</p>
`
})
export class MySelectComponent {
cities: City[] = [
{ id: 1, name: 'Москва' },
{ id: 2, name: 'Санкт-Петербург' },
{ id: 3, name: 'Казань' }
];
selectedCityId: number | null = null;
selectedCityName: string = '';
onCityChange(cityId: number): void {
// Ищем город по id в массиве
const selectedCity = this.cities.find(city => city.id === cityId);
this.selectedCityName = selectedCity ? selectedCity.name : 'Неизвестный город';
console.log('Выбран город с ID:', cityId);
}
}
Почему это работает и важные моменты:
- [(ngModel)] — это двусторонняя привязка. Когда пользователь выбирает опцию, свойство
selectedCityId автоматически обновляется.
- (ngModelChange) — это событие, которое срабатывает после обновления модели. В него передаётся новое значение (в нашем случае —
number).
- [ngValue] — предпочтительнее, чем
[value], так как ngValue может передавать любые типы данных (объекты, числа), а [value] всегда преобразует в строку. Для числовых ID это не критично, но для объектов — обязательно.
- Типизация: мы объявили
selectedCityId: number | null, что даёт подсказки TypeScript и предотвращает ошибки.
Альтернатива без отдельного метода (inline):
<select [(ngModel)]="selectedCityId" (ngModelChange)="selectedCityName = cities.find(c => c.id === $event)?.name || ''">
<option *ngFor="let city of cities" [ngValue]="city.id">{{ city.name }}</option>
</select>
Но лучше выносить логику в метод — это делает код читаемее и тестируемее.
Этот подход работает во всех версиях Angular (2+, включая 14, 15, 16, 17). Он безопаснее, чем прямой доступ к event.target.value, и полностью соответствует принципам Angular.
<<>>
Альтернативный подход: привязка к объекту целиком
Иногда удобнее хранить не ID, а весь выбранный объект. Это избавляет от необходимости искать элемент в массиве. Используйте [ngValue]="city" (передаём весь объект) и привязку к свойству типа City | null.
// my-select.component.ts
export class MySelectComponent {
cities: City[] = [
{ id: 1, name: 'Москва' },
{ id: 2, name: 'Санкт-Петербург' },
{ id: 3, name: 'Казань' }
];
selectedCity: City | null = null; // храним объект целиком
onCityChange(city: City): void {
console.log('Выбран город:', city.name);
// Теперь у нас есть доступ ко всем полям объекта city
this.selectedCity = city;
}
}
<!-- template -->
<select [(ngModel)]="selectedCity" (ngModelChange)="onCityChange($event)">
<option *ngFor="let city of cities" [ngValue]="city">
{{ city.name }}
</option>
</select>
<p>Вы выбрали: {{ selectedCity?.name }} (ID: {{ selectedCity?.id }})</p>
Важно: При таком подходе Angular сравнивает объекты по ссылке. Если вы динамически обновляете массив cities, убедитесь, что объекты остаются теми же самыми (не создавайте новые), иначе выбранное значение может сброситься. Для большинства простых случаев это самый удобный вариант.