Angular Material Select 封装为子组件时如何编程设置选中值
问题根因
你当前的封装方式不符合Angular表单的规范,才需要手动触发@Input变更来执行compareWith。compareWith本身不需要手动调用,只要满足两个条件就会自动执行:
- mat-select绑定的FormControl值发生变更
- mat-option的选项列表已完成渲染
解决方案
步骤1:改造select子组件,实现ControlValueAccessor接口
让你封装的select-multiple-example成为合法的Angular表单控件,支持直接绑定formControl/formControlName,不需要传递整个formGroup或者单独的选中值参数。
首先在子组件的@Component装饰器中添加表单控件提供者:
import { NG_VALUE_ACCESSOR, ControlValueAccessor, forwardRef } from '@angular/forms'; @Component({ // 原有组件配置不变 providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SelectMultipleExample), multi: true } ] })
然后在子组件类中实现ControlValueAccessor的核心方法:
export class SelectMultipleExample implements ControlValueAccessor { selectControl = new FormControl(); // 下拉选项列表根据你的实际业务定义 options = []; onChange = (val: any) => {}; onTouched = () => {}; // 表单值写入时自动触发 writeValue(val: any): void { this.selectControl.setValue(val, { emitEvent: false }); } registerOnChange(fn: any): void { this.onChange = fn; // 子组件值变化时同步到父表单 this.selectControl.valueChanges.subscribe(val => this.onChange(val)); } registerOnTouched(fn: any): void { this.onTouched = fn; } setDisabledState?(isDisabled: boolean): void { isDisabled ? this.selectControl.disable() : this.selectControl.enable(); } // 自定义比较逻辑,根据实际业务修改匹配字段 compareFn(o1: any, o2: any): boolean { return o1 && o2 ? o1.id === o2.id : o1 === o2; } }
子组件的模板直接绑定formControl和compareWith即可:
<mat-form-field appearance="fill"> <mat-label>下拉选择</mat-label> <mat-select [formControl]="selectControl" [compareWith]="compareFn"> <mat-option *ngFor="let item of options" [value]="item">{{item.label}}</mat-option> </mat-select> </mat-form-field>
步骤2:父组件直接通过表单赋值实现回显
父组件不需要单独传递selectedValue或者整个formGroup给子组件,加载完数据后直接调用表单的patchValue/setValue方法赋值即可自动触发回显,compareWith会自动执行匹配对应选项:
// 接口返回数据后直接赋值 loadFormData() { this.contactForm.patchValue({ fullName: '返回的姓名', email: '返回的邮箱', // 这里的字段名和你绑定子组件的formControlName一致 selectField: '接口返回的选中值对象' }) }
父组件模板简化为:
<form [formGroup]="contactForm" > <mat-form-field class="example-full-width" appearance="fill"> <mat-label>Full Name </mat-label> <input matInput placeholder="Full Name" formControlName="fullName"> </mat-form-field> <br> <mat-form-field class="example-full-width" appearance="fill"> <mat-label>Email </mat-label> <input type = "email" matInput placeholder="Email" formControlName="email"> </mat-form-field> <br> <!-- 直接绑定formControlName即可,不需要额外传参 --> <select-multiple-example formControlName="selectField"></select-multiple-example> </form>
注意事项
如果下拉选项是异步加载的,只要选项列表更新完成,Angular会自动重新执行compareWith匹配已赋值的表单值,不需要额外手动处理。
内容的提问来源于stack exchange,提问作者RoyBarOn
相关产品推荐
相关产品推荐

