Angular自定义FormControl配置updateOn blur功能失效如何解决?
问题根因
你当前的自定义表单控件实现和Angular updateOn: 'blur' 的触发逻辑不匹配,核心问题有3个:
- 输入时(keyup事件)就直接调用了
markAsTouched()和onChange(),提前触发了表单校验、值更新,和updateOn: 'blur'要求的「失焦时才同步值、触发校验」逻辑冲突 writeValue方法仅在传入值非空时才赋值,初始值为空字符串时不会更新组件内部value,导致表单初始值同步错误- 没有在失焦事件中统一处理值同步、触摸状态标记逻辑,和Angular表单的更新时机不匹配
具体修改方案
1. 调整CustomTextareaComponent的TS代码
export class CustomTextareaComponent implements ControlValueAccessor { @Input() placeholder = '' // give a transloco string directly @Input() limit = 500 @Input() error: boolean = false value: string | null = null currentNumberOfCharacters: number = 0 isActive: boolean | undefined onChange: any = () => { } onTouch: any = () => { } touched = false disabled = false // 输入时仅更新组件内部状态,不通知外层表单 changes(event: Event) { if (this.disabled) return this.value = event?.target ? (event?.target as HTMLTextAreaElement).value : '' this.currentNumberOfCharacters = this.value.length } // 新增失焦处理方法,仅在失焦时同步状态给外层表单 handleBlur() { this.isActive = false if (this.disabled) return this.markAsTouched() this.onChange(this.value) } registerOnChange(providedFunction: any) { this.onChange = providedFunction } registerOnTouched(providedFunction: any) { this.onTouch = providedFunction } // 修正空值处理逻辑,空字符串也需要赋值 writeValue(providedValue: any) { this.value = providedValue ?? '' this.currentNumberOfCharacters = this.value.length } setDisabledState(providedDisabledVal: any) { this.disabled = providedDisabledVal } markAsTouched() { if (!this.touched) { this.onTouch() this.touched = true } } }
2. 调整CustomTextareaComponent的HTML代码
修改textarea的失焦事件绑定,调用新增的handleBlur方法:
<div class="plnd-textarea"> <div class="plnd-textarea__field-container" [class.plnd-textarea__field-container--written]="value" [class.plnd-textarea__field-container--active]="isActive" [class.plnd-textarea__field-container--error]="error"> <textarea [placeholder]="placeholder | transloco" [value]="value" (keyup)="changes($event)" (focus)="isActive=true" (focusout)="handleBlur()" [maxLength]="limit" class="plnd-textarea__field" ></textarea> </div> <p class="plnd-textarea__characters">{{ currentNumberOfCharacters }}/{{ limit }} {{ 'common.characters' | transloco }}</p> </div>
3. 同步修改custom-input组件
如果你的custom-input自定义控件逻辑和textarea一致,按照上面的逻辑同步修改即可:输入时仅更新内部状态,失焦时再同步值给外层表单、标记已触摸,修正writeValue的空值处理逻辑。
效果验证
修改完成后:
- 输入字符时仅更新组件内部的输入显示和字符计数,不会提前触发表单校验,失焦后才会同步值、触发校验,不会出现输入时就报必填错误的问题
- 表单提交时能正确拿到所有自定义控件的最新值,不会出现空值问题
- 同时兼容
updateOn: 'change'、updateOn: 'submit'的原有配置,不影响之前的正常逻辑
内容的提问来源于stack exchange,提问作者PepeW
相关产品推荐
相关产品推荐

