Angular mat-select多选:切换数据源后保留历史已选值
解决方案:保留已选历史数据同时限制下拉可选范围
要实现显示已保存的非在售车辆(car2、car5),同时仅允许选择在售车辆(carsSold),可以通过合并数据源+禁用非在售选项的方式实现,具体步骤如下:
1. 组件中构造合并后的下拉数据源
在组件类中创建计算属性,合并在售车辆数组和已选的非在售车辆,确保已保存的历史选择能出现在下拉列表中:
import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators, AbstractControl, ValidationErrors } from '@angular/forms'; @Component({ selector: 'app-shop-form', templateUrl: './shop-form.component.html' }) export class ShopFormComponent implements OnInit { shopForm!: FormGroup; // 原始全量车辆数据 cars = [ { id: 1, name: "car1", sold: true }, { id: 2, name: "car2", sold: false }, { id: 3, name: "car3", sold: true }, { id: 4, name: "car4", sold: true }, { id: 5, name: "car5", sold: false } ]; // 在售车辆数据源 carsSold = [ { id: 1, name: "car1", sold: true }, { id: 3, name: "car3", sold: true }, { id: 4, name: "car4", sold: true } ]; constructor(private fb: FormBuilder) {} ngOnInit(): void { // 初始化表单,加载数据库保存的已选车辆ID this.shopForm = this.fb.group({ carIds: [[1,2,5], [Validators.required, this.validateSoldCars()]] }); } // 构造下拉列表用的合并数据源 get dropdownCars() { const selectedIds = this.shopForm.get('carIds')?.value || []; // 筛选出已选但不在在售列表中的车辆 const selectedNonSold = this.cars.filter(car => selectedIds.includes(car.id) && !this.carsSold.some(s => s.id === car.id) ); // 合并并去重,避免在售车辆重复显示 return [...this.carsSold, ...selectedNonSold].filter((car, idx, self) => self.findIndex(c => c.id === car.id) === idx ); } // 可选:自定义验证器,确保提交时仅包含在售车辆 validateSoldCars(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const selectedIds = control.value as number[]; const validIds = this.carsSold.map(c => c.id); const invalidIds = selectedIds.filter(id => !validIds.includes(id)); return invalidIds.length > 0 ? { invalidNonSold: '不能选择已下架车辆' } : null; }; } }
2. 修改HTML模板,配置下拉选项
在模板中使用合并后的数据源,并对非在售车辆设置禁用状态,同时添加标记提示用户:
<mat-form-field> <mat-label>Cars</mat-label> <mat-select formControlName="carIds" multiple required> <mat-option *ngFor="let car of dropdownCars" [value]="car.id" [disabled]="!car.sold" > {{car.name}} <!-- 给非在售车辆添加视觉标记 --> <span *ngIf="!car.sold" style="color: #999;"> [已下架]</span> </mat-option> </mat-select> <!-- 显示验证错误信息 --> <mat-error *ngIf="shopForm.get('carIds')?.hasError('invalidNonSold')"> {{shopForm.get('carIds')?.getError('invalidNonSold')}} </mat-error> </mat-form-field>
效果说明
- 打开表单时,已保存的car1、car2、car5都会显示在已选区域中
- 下拉列表仅展示在售车辆(car1、car3、car4)和已选的非在售车辆(car2、car5)
- 非在售车辆选项被禁用,无法被重新选择,但已选状态会保留
- 可选的自定义验证器会阻止用户提交包含非在售车辆的表单(如果需要)
内容的提问来源于stack exchange,提问作者Stranger
相关产品推荐
相关产品推荐

