自定义mat-chip-list控件表单首次打开触发mat-error必填报错的解决方法
问题原因分析
- 校验触发逻辑不合理:你当前
mat-error的显示条件只要isInitialized=true且无值就触发,而isInitialized在组件初始化完成(ngOnInit/ngAfterViewInit)就会被设为true,表单刚加载完成无初始值时会直接触发错误提示,完全没有考虑用户交互状态 - 选中值状态同步遗漏:
hasValue仅在选中、删除芯片时更新,若父组件传入的selectedOptions初始为空、或父组件动态修改了该输入值,hasValue不会自动同步,导致校验状态错误 - 未复用Angular表单自带状态:你完全手写了校验逻辑,没有关联Angular表单自带的
touched(用户是否交互过)、dirty(值是否修改过)、submitted(表单是否提交)等状态,不符合Angular表单的设计逻辑
最小改动解决方案(不用重构现有逻辑)
不需要重写现有逻辑,只需要做几处小修改就能满足需求:
- 新增交互状态变量与值监听
在TS文件中修改如下代码:
// 新增标记用户是否交互过控件 isTouched = false; // 新增接收父表单提交状态的输入属性 @Input() isSubmitted = false; // 用setter监听selectedOptions变化,自动更新hasValue @Input() set selectedOptions(val: Options[]) { this._selectedOptions = val; this.hasValue = val.length > 0; } get selectedOptions(): Options[] { return this._selectedOptions; } private _selectedOptions: Options[] = []; // 新增标记控件为已交互的方法 markAsTouched() { this.isTouched = true; }
- 修改输入框绑定,增加失焦事件
在HTML的input标签上添加失焦事件绑定:
<input #optionInput type="text" [placeholder]="placeholder" [formControl]="formControl" [matAutocomplete]="optionAutoComplete" [matChipInputFor]="optionList" [required]="required" (blur)="markAsTouched()" />
- 修改mat-error显示条件
仅在用户交互过/表单提交过,且确实无值时才显示错误:
<mat-error *ngIf="required && !hasValue && (isTouched || isSubmitted)"> {{ label }} is <strong>required</strong> </mat-error>
- 父组件使用时传入表单提交状态
父组件表单提交时将提交状态传入自定义控件即可:
<app-linq-chips label="Entities" placeholder="Add Entity..." [options]="entityOptions" [selectedOptions]="selectedEntities" [isSubmitted]="formGroup.submitted" [hint]="entityListHasDisabledOptions ? 'Please remove this contact from any roles for an entity prior to removing their association to that entity.' : undefined" (onRemoved)="removeEntity($event)" > </app-linq-chips>
更规范的长期方案
如果后续要复用这个控件,建议实现ControlValueAccessor接口,让自定义芯片控件成为Angular表单体系的合法控件,自动继承FormControl的所有状态,无需自己维护校验逻辑,直接使用Angular自带的Validators.required即可,代码更简洁也更易维护。
内容的提问来源于stack exchange,提问作者lynn0712
相关产品推荐
相关产品推荐

