【Angular】添加和更改下拉菜单选项
简而言之
使用反应式表单可以带来幸福。
想要实现的目标
-
- ドロップダウンにサーバAPI経由でDBから取得した内容を表示する
-
- 同様に、サーバAPI経由でドロップダウン項目の追加、変更をおこなう
- 追加後は追加された項目を、変更後は変更された項目を選択状態にする
环境
Node.js
Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境。
root@user:/app/my-app# node --version
v12.7.0
角度/角度度量
"dependencies": {
"@angular/animations": "~8.0.0",
"@angular/common": "~8.0.0",
"@angular/compiler": "~8.0.0",
"@angular/core": "~8.0.0",
"@angular/forms": "~8.0.0",
"@angular/platform-browser": "~8.0.0",
"@angular/platform-browser-dynamic": "~8.0.0",
"@angular/router": "~8.0.0"
}
源代码
模块
导入ReactiveFormsModule。
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
// other imports ...
ReactiveFormsModule
]
export class AppModule {}
组件
import { Component, OnInit } from '@angular/core';
import { Hero, HeroService } from '../hero.service';
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
heroes: Hero[]; // ドロップダウン表示リスト
selectedHeroControl = new FormControl();
// オブジェクト配列を扱う場合はコンペア関数を実装する必要がある
compareHero(hero1: Hero, hero2: Hero): boolean {
return hero1.id === hero2.id;
}
constructor(private heroService: HeroService) {}
async ngOnInit() {
this.heroes = await this.heroService.getHeroes().toPromise();
// ドロップダウンの初期値を設定
this.selectedHeroControl = new FormControl(this.heroes[0]);
}
async onClickAddHero(name: string) {
const addHero = await this.heroService
.addHero({ name } as Hero)
.toPromise();
this.heroes = await this.heroService.getHeroes().toPromise();
// 追加したHeroを選択状態にする
this.selectedHeroControl.setValue(addHero);
}
async onClickUpdateHero(name: string) {
const updateHero = new Hero(this.selectedHeroControl.value.id, name);
const updatedHero = await this.heroService
.updateHero(updateHero)
.toPromise();
this.heroes = await this.heroService.getHeroes().toPromise();
// 変更したHeroを選択状態にする
this.selectedHeroControl.setValue(updatedHero);
}
}
模板
<select [formControl]="selectedHeroControl" [compareWith]="compareHero">
<option [ngValue]="hero" *ngFor="let hero of heroes">{{ hero.name }}</option>
</select>
<div>
<label
>Hero name:
<input type="text" #heroName />
</label>
<button (click)="onClickAddHero(heroName.value)">追加</button>
<button (click)="onClickUpdateHero(heroName.value)">更新</button>
</div>
服务
不细说了。
import { Injectable } from '@angular/core';
import { Observable} from 'rxjs';
export class Hero {
id: number;
name: string;
constructor(id: number, name: string) {
this.id = id;
this.name = name;
}
}
@Injectable({
providedIn: 'root'
})
export class HeroService {
getHeroes(): Observable<Hero[]> {
// サーバAPIをCallし、取得した一覧を返す
}
addHero(hero: Hero): Observable<Hero> {
// サーバAPIをCallし、追加したオブジェクトを返す
}
updateHero(hero: Hero): Observable<Hero> {
// サーバAPIをCallし、更新したオブジェクトを返す
}
}
补充解释
比较函数
Angular使用对象ID来唯一标识选项。当进行更改时,当前显示的项目和从服务器API重新获取的项目添加的项目的对象ID是不同的,因此需要实现比较算法来判断它们是否匹配。
export class AppComponent {
compareHero(hero1: Hero, hero2: Hero): boolean {
return hero1.id === hero2.id;
}
}
<select [compareWith]="compareHero">
检测下拉菜单的更改的方法
使用FromControl的valueChanges功能。
async ngOnInit() {
this.selectedHeroControl.valueChanges.subscribe(hero => {
console.log(`Selected Hero: ${hero.name}`);
});
}
}
请参考
-
- Reactive Forms
- SelectControlValueAccessor