Angular FormControl无法检测numeric输入指令对matInput的值修改如何解决
问题根因
你当前的数值指令是直接修改nativeElement.value这类原生DOM属性,Angular响应式表单默认只会监听用户交互触发的输入类事件来同步值,直接修改DOM的操作不会被FormControl自动捕获,所以出现了输入框显示值和表单实际值不一致的问题。
方案1:修改指令内部逻辑(推荐,从根源解决)
在指令中注入绑定的NgControl实例,每次修改输入框值的时候同步更新到FormControl,修改后的指令代码如下:
import { Directive, ElementRef, HostListener, Input, Optional } from "@angular/core"; import { NgControl } from "@angular/forms"; // 新增导入 @Directive({ selector: "[numeric]" }) export class NumericDirective { @Input("decimals") decimals: number = 0; @Input("negative") negative: number = 0; @Input("separator") separator: string = "."; private checkAllowNegative(value: string) { if (this.decimals <= 0) { return String(value).match(new RegExp(/^-?\d+$/)); } else { var regExpString = "^-?\\s*((\\d+(\\"+ this.separator +"\\d{0," + this.decimals + "})?)|((\\d*(\\"+ this.separator +"\\d{1," + this.decimals + "}))))\\s*$"; return String(value).match(new RegExp(regExpString)); } } private check(value: string) { if (this.decimals <= 0) { return String(value).match(new RegExp(/^\d+$/)); } else { var regExpString = "^\\s*((\\d+(\\"+ this.separator +"\\d{0," + this.decimals + "})?)|((\\d*(\\"+ this.separator +"\\d{1," + this.decimals + "}))))\\s*$"; return String(value).match(new RegExp(regExpString)); } } private run(oldValue: any) { setTimeout(() => { let currentValue: string = this.el.nativeElement.value; let allowNegative = this.negative > 0 ? true : false; let finalValue = currentValue; if (allowNegative) { if ( !["", "-"].includes(currentValue) && !this.checkAllowNegative(currentValue) ) { finalValue = oldValue; } } else { if (currentValue !== "" && !this.check(currentValue)) { finalValue = oldValue; } } // 同步值到DOM this.el.nativeElement.value = finalValue; // 如果绑定了表单控件就同步更新表单值 if (this.ngControl?.control) { this.ngControl.control.setValue(finalValue); } }); } constructor( private el: ElementRef, @Optional() private ngControl: NgControl // 注入当前输入框绑定的表单控件 ) {} @HostListener("keydown", ["$event"]) onKeyDown(event: KeyboardEvent) { this.run(this.el.nativeElement.value); } @HostListener("paste", ["$event"]) onPaste(event: ClipboardEvent) { this.run(this.el.nativeElement.value); } }
方案2:不改指令,在模板层加事件监听(临时适配)
如果不方便修改第三方指令的源码,可以直接在输入框上新增input事件监听,手动把输入框的值同步到FormControl,修改后的输入框代码如下:
<input matInput numeric type="number" formControlName="quantity" [placeholder]="'Available Quantity ' + data.item.quantity" (input)="actionFormGroup.get('quantity')?.setValue($event.target.value)">
额外注意点
你当前给quantity控件加的数字正则校验,和指令的非负整数规则是匹配的,修改后校验规则可以正常触发。
内容的提问来源于stack exchange,提问作者Yaxet
相关产品推荐
相关产品推荐

