You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular中点击mat-select后显示mat-option内容的问题求助

问题:点击mat-select后无法显示对应的宝可梦选项内容?

我正在做一个宝可梦相关项目,当前遇到的问题是:点击对应的mat-select后,无法显示对应的mat-option内容。以下是我的现有代码:

service.ts 代码

getTrainersNames(): Observable<Array<string>>{
  return this.http.get<Trainer[]>(`${this.apiUrl1}`).pipe(
    map((entrenadores: Trainer[]) => {
      return entrenadores.map((entrenador: Trainer) => entrenador.fullName);
    })
  );
}

getPokemonsOfATrainer(nombreEntrenador: string): Observable<Array<Pokemon[]>> {
  return this.http.get<Trainer[]>(`${this.apiUrl1}?fullName=${nombreEntrenador}`).pipe(
    map((entrenadores: Trainer[]) => {
      return entrenadores.map((entrenador: Trainer) => entrenador.pokemons);
    })
  );
}

controller.ts 代码

// INSIDE ngOnInit
this.obtainData.getTrainersNames().subscribe({
  next: (nombres: string[]) => {
    this.trainerNames = nombres
  },
  error: (err: Error) => console.log('Hubo un error en el observable '),
  complete: () => {
    console.log('Observer got a complete notification')
  }, 
});

this.obtainData.getPokemonsOfATrainer(this.assignTrainerName()).subscribe( {
  next: (pokemones: Pokemon[][]) => this.pokemons = pokemones[0],
  error: (err: Error) => console.log('Hubo un error en el observable '),
  complete: () => console.log('Observer got a complete notification'), 
});
// INSIDE ngAfterViewInit

assignTrainerName() {
  // Get the selected value from the mat-select element
  const selectedValue = this.attacksForm.controls['trainerName'].value;

  // Check if the selected value is in the this.trainerNames array
  const selectedTrainer = this.trainerNames.find(name => name === selectedValue);

  console.log(selectedTrainer);

  // If the selected value is in the array, assign it to this.trainerName
  if (selectedTrainer) {
    this.trainerName = selectedTrainer;
  }

  return this.trainerName;
}

模板代码

<!--INSIDE a form-->
<mat-form-field appearance="standard">
    <mat-label>Selecciona un pokemon</mat-label>
    <mat-select matNativeControl formControlName="pokemonName" #matSelect>
      <mat-option *ngFor="let pokemon of pokemons" [value]="pokemon.name">
        {{pokemon.name}}
      </mat-option>
    </mat-select>
</mat-form-field>

请问如何调整才能让mat-option正常显示内容?


解决方案

你的核心问题在于没有监听训练师选择的变化,并且在ngOnInit中过早调用了getPokemonsOfATrainer——此时用户还没选择任何训练师,assignTrainerName返回的是undefined或者空值,导致获取不到有效宝可梦数据。

步骤1:移除无效的初始订阅

删除ngOnInit中对getPokemonsOfATrainer的初始订阅,因为这时候没有选中的训练师,请求毫无意义。

步骤2:监听训练师控件的变化

在ngOnInit中添加对trainerName表单控件的valueChanges监听,当用户选择训练师时,再去请求对应的宝可梦列表:

// INSIDE ngOnInit
this.obtainData.getTrainersNames().subscribe({
  next: (nombres: string[]) => {
    this.trainerNames = nombres;
    // 可选:如果需要默认选中第一个训练师
    if (nombres.length > 0) {
      this.attacksForm.controls['trainerName'].setValue(nombres[0]);
    }
  },
  error: (err: Error) => console.log('Error al obtener nombres de entrenadores'),
  complete: () => console.log('Obtención de nombres completada'), 
});

// 监听训练师选择变化
this.attacksForm.controls['trainerName'].valueChanges.pipe(
  // 过滤空值或无效值
  filter(selectedName => !!selectedName && this.trainerNames.includes(selectedName)),
  // 避免频繁请求,可选
  debounceTime(300)
).subscribe(selectedName => {
  this.obtainData.getPokemonsOfATrainer(selectedName).subscribe({
    next: (pokemones: Pokemon[][]) => {
      // 确保取到有效的宝可梦数组
      this.pokemons = pokemones[0] || [];
      // 可选:清空之前选中的宝可梦
      this.attacksForm.controls['pokemonName'].setValue(null);
    },
    error: (err: Error) => console.log('Error al obtener pokemones del entrenador'),
    complete: () => console.log('Obtención de pokemones completada'), 
  });
});

步骤3:移除冗余的assignTrainerName函数

现在不需要这个函数了,因为我们直接通过valueChanges获取选中的训练师名称,并且已经做了有效性校验(filter操作符)。

步骤4:优化内存泄漏问题(可选但推荐)

如果组件会被销毁,记得取消订阅valueChanges和HTTP请求,避免内存泄漏。可以使用takeUntil操作符:

// 在组件中定义一个销毁信号
private destroy$ = new Subject<void>();

// 在ngOnInit中修改监听逻辑
this.attacksForm.controls['trainerName'].valueChanges.pipe(
  filter(selectedName => !!selectedName && this.trainerNames.includes(selectedName)),
  debounceTime(300),
  takeUntil(this.destroy$) // 组件销毁时自动取消订阅
).subscribe(selectedName => {
  this.obtainData.getPokemonsOfATrainer(selectedName).pipe(
    takeUntil(this.destroy$)
  ).subscribe({
    // ... 之前的逻辑
  });
});

// 在ngOnDestroy中发送销毁信号
ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}

额外建议:使用Async管道简化代码

你也可以直接在模板中使用async管道,避免手动订阅:

  1. 在controller中定义一个pokemons$ Observable:
pokemons$!: Observable<Pokemon[]>;

// INSIDE ngOnInit
this.pokemons$ = this.attacksForm.controls['trainerName'].valueChanges.pipe(
  filter(selectedName => !!selectedName && this.trainerNames.includes(selectedName)),
  debounceTime(300),
  switchMap(selectedName => 
    this.obtainData.getPokemonsOfATrainer(selectedName).pipe(
      map(pokemones => pokemones[0] || [])
    )
  )
);
  1. 修改模板代码:
<mat-form-field appearance="standard">
    <mat-label>Selecciona un pokemon</mat-label>
    <mat-select matNativeControl formControlName="pokemonName">
      <mat-option *ngFor="let pokemon of pokemons$ | async" [value]="pokemon.name">
        {{pokemon.name}}
      </mat-option>
    </mat-select>
</mat-form-field>

这样可以完全省去手动订阅和取消订阅的逻辑,代码更简洁且安全。


内容的提问来源于stack exchange,提问作者Eric Díaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:10:31