Angular中*ngFor与*ngIf组合导致Mat-Select选中项文本不显示
首先明确两个指令的核心区别:
*ngIf是结构性指令,条件不满足时会把对应的<mat-option>完全从DOM树中移除[hidden]只是通过CSSdisplay: none隐藏元素,<mat-option>节点仍然留在DOM中
你的场景里,当用*ngIf过滤选项时,如果没特意排除当前下拉框自己的选中值,会导致当前选中的选项也被移除DOM。而Mat-Select需要依赖DOM中的<mat-option>来匹配选中值并渲染对应的文本——没有了对应的DOM节点,自然无法显示选中的文本。
而[hidden]只是把其他下拉框选中的选项藏起来,当前自己选中的选项始终在DOM里,Mat-Select能正常找到并渲染文本。
组件TS代码示例
import { Component } from '@angular/core'; import { FormGroup, FormBuilder } from '@angular/forms'; interface Option { id: number; label: string; } @Component({ selector: 'app-select-demo', templateUrl: './select-demo.component.html', styleUrls: ['./select-demo.component.css'] }) export class SelectDemoComponent { form: FormGroup; options: Option[] = [ { id: 1, label: '选项A' }, { id: 2, label: '选项B' }, { id: 3, label: '选项C' }, { id: 4, label: '选项D' } ]; constructor(private fb: FormBuilder) { this.form = this.fb.group({ select1: [null], select2: [null], select3: [null], select4: [null] }); } // 获取所有已选中的选项ID(排除当前控件的选中值) getSelectedIds(excludeControlName: string): number[] { const selectedIds: number[] = []; Object.keys(this.form.controls).forEach(controlName => { if (controlName !== excludeControlName) { const value = this.form.get(controlName)?.value; if (value) { selectedIds.push(value); } } }); return selectedIds; } // 判断选项是否需要隐藏(用于[hidden]方案) shouldHideOption(optionId: number, excludeControlName: string): boolean { const selectedIds = this.getSelectedIds(excludeControlName); return selectedIds.includes(optionId); } // 错误的*ngIf判断逻辑:把所有选中的都排除,包括当前自己的 shouldShowOptionWrong(optionId: number): boolean { const allSelectedIds = Object.values(this.form.controls).map(ctrl => ctrl.value).filter(v => v); return !allSelectedIds.includes(optionId); } // 正确的*ngIf判断逻辑:排除其他控件的选中值,保留当前自己的 shouldShowOptionCorrect(optionId: number, excludeControlName: string): boolean { const selectedIds = this.getSelectedIds(excludeControlName); return !selectedIds.includes(optionId); } }
错误的*ngIf实现(选中项不显示)
<form [formGroup]="form"> <mat-form-field> <mat-label>下拉框1</mat-label> <mat-select formControlName="select1"> <!-- 错误:全局过滤所有选中值,当前选中的选项会被移除DOM --> <mat-option *ngFor="let opt of options" *ngIf="shouldShowOptionWrong(opt.id)" [value]="opt.id"> {{ opt.label }} </mat-option> </mat-select> </mat-form-field> <!-- 其他3个下拉框结构相同,略 --> </form>
正确的*ngIf实现(可正常显示选中项)
<form [formGroup]="form"> <mat-form-field> <mat-label>下拉框1</mat-label> <mat-select formControlName="select1"> <!-- 正确:仅排除其他下拉框的选中值,保留当前自己的选中项 --> <mat-option *ngFor="let opt of options" *ngIf="shouldShowOptionCorrect(opt.id, 'select1')" [value]="opt.id"> {{ opt.label }} </mat-option> </mat-select> </mat-form-field> <mat-form-field> <mat-label>下拉框2</mat-label> <mat-select formControlName="select2"> <mat-option *ngFor="let opt of options" *ngIf="shouldShowOptionCorrect(opt.id, 'select2')" [value]="opt.id"> {{ opt.label }} </mat-option> </mat-select> </mat-form-field> <!-- 下拉框3、4同理替换对应的controlName --> </form>
<form [formGroup]="form"> <mat-form-field> <mat-label>下拉框1</mat-label> <mat-select formControlName="select1"> <mat-option *ngFor="let opt of options" [hidden]="shouldHideOption(opt.id, 'select1')" [value]="opt.id"> {{ opt.label }} </mat-option> </mat-select> </mat-form-field> <!-- 其他3个下拉框结构相同,替换controlName即可 --> </form>
总结
- 若坚持用
*ngIf,必须在过滤逻辑中排除当前下拉框自己的选中值,否则选中的选项会被移除DOM,导致Mat-Select无法渲染文本 [hidden]方案更简洁,因为它仅隐藏元素不删除DOM,当前选中的选项始终存在,Mat-Select能正常匹配到对应的选项
内容的提问来源于stack exchange,提问作者brian
相关产品推荐
相关产品推荐

