Angular 使用带有@HostListener 的指令来更新 ReactiveForm 的输入值是将输入设置为 ngValid 而不是 ngInvalid
Angular Using Directive with @HostListener to Update Input Value of ReactiveForm is Setting Input to ngValid Instead of ngInvalid
我在 ReactiveForm
FormControl
上放置了一个货币属性指令,它在输入事件 (onKeyDown) 上使用 @HostListener
来删除所有无效字符(字母和符号)因为它们被输入到输入中,但允许数字和小数。 BUT,如果您在空的输入字段中键入无效字符(即 a
)并且它被指令删除,则模型 不是 已更新。
我使用货币指令添加了 plunker 设置。理解我的问题的步骤:
- 键入
123a
您没有在输入中得到 a
,因为不允许输入任何字母,并且由于表单无效,按钮被禁用 (好)
- 键入
123.456
您没有在输入中得到 6
因为只允许 2 位小数,并且由于表单无效而禁用了按钮 (good )
- 键入
a
你没有在输入中得到 a
,但是 butt 已启用,因为模型认为它有一个 a
,即使 UI 不显示 (差)
您可以通过单击按钮并在控制台中查看记录 this.form.value
并显示 { amount: 'a' }
来验证模型未更新。如果您接下来键入一个有效字符,该模型将仅包含该字符,并且 a
将被删除。所以只有在这种情况下,模型没有正确更新。
这个问题在 AngularJS 中很容易解决,使用 ngModel validator and parser pipes
、modelValue
、$setViewValue
和 $render()
更新并强制 AngularJS 到 运行 一个 $digest。在 Angular 中如何做到这一点?
这是我的属性指令中的一个片段,它成功地删除了不需要的字符:
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
const input = event.target as HTMLInputElement;
// Only numbers and decimals
let trimmed = input.value.replace(/[^\d\.,]+/g, '');
// Only a single decimal and choose the first one found
if (trimmed.split('.').length > 2) {
trimmed = trimmed.replace(/\.([^\.]*)$/, '');
}
// Cannot start with decimal typed or pasted
if (trimmed.indexOf('.') === 0) { trimmed = ''; }
// AngularJS "like" solution would be something like:
// ngModelCtrl.$setViewValue(trimmed);
// ngModelCtrl.$render();
// Angular solution is???
input.value = trimmed;
}
最近的 angular 4 版本引入了一个新指令来处理这些情况
<input [name]="fullName" pattern="[a-zA-Z ]*" [(ngModel)]="...">
在模式中你可以指定任何正则表达式
更新:根据评论,如果您试图限制用户输入字符,您可以使用自定义指令。
为你的指令函数使用下面的代码
@HostListener('keydown') onKeydown() {
let value= this.el.nativeElement.value;
let key= value.charCodeAt(value.length -1])
let strippedString ='';
if(!((key > 64 && key < 91) || (key> 96 && key< 123) || key== 8 || key== 32 || (key>= 48 && key<= 57)){
strippedString = this.el.nativeElement.value.substring(0,value.length-1)
this.el.nativeElement.value = strippedString
}
所以我确实找到了一个解决方案,使用 NgControl
注入 private ngControl: NgControl
然后访问它的控件 属性 this.ngControl.control.patchValue(newValue);
,它更新输入字段模型我的 onKeyDown
活动中的 ReactiveForm
- 请参阅 plunker
BUT 基于智能组件和哑组件的使用 EventEmitter
实际上是一个更好的解决方案,它将值从输入 - plunker(感谢 Todd Motto 和他的 Ultimate Angular 课程)
我在 ReactiveForm
FormControl
上放置了一个货币属性指令,它在输入事件 (onKeyDown) 上使用 @HostListener
来删除所有无效字符(字母和符号)因为它们被输入到输入中,但允许数字和小数。 BUT,如果您在空的输入字段中键入无效字符(即 a
)并且它被指令删除,则模型 不是 已更新。
我使用货币指令添加了 plunker 设置。理解我的问题的步骤:
- 键入
123a
您没有在输入中得到a
,因为不允许输入任何字母,并且由于表单无效,按钮被禁用 (好) - 键入
123.456
您没有在输入中得到6
因为只允许 2 位小数,并且由于表单无效而禁用了按钮 (good ) - 键入
a
你没有在输入中得到a
,但是 butt 已启用,因为模型认为它有一个a
,即使 UI 不显示 (差)
您可以通过单击按钮并在控制台中查看记录 this.form.value
并显示 { amount: 'a' }
来验证模型未更新。如果您接下来键入一个有效字符,该模型将仅包含该字符,并且 a
将被删除。所以只有在这种情况下,模型没有正确更新。
这个问题在 AngularJS 中很容易解决,使用 ngModel validator and parser pipes
、modelValue
、$setViewValue
和 $render()
更新并强制 AngularJS 到 运行 一个 $digest。在 Angular 中如何做到这一点?
这是我的属性指令中的一个片段,它成功地删除了不需要的字符:
@HostListener('input', ['$event'])
onKeyDown(event: KeyboardEvent) {
const input = event.target as HTMLInputElement;
// Only numbers and decimals
let trimmed = input.value.replace(/[^\d\.,]+/g, '');
// Only a single decimal and choose the first one found
if (trimmed.split('.').length > 2) {
trimmed = trimmed.replace(/\.([^\.]*)$/, '');
}
// Cannot start with decimal typed or pasted
if (trimmed.indexOf('.') === 0) { trimmed = ''; }
// AngularJS "like" solution would be something like:
// ngModelCtrl.$setViewValue(trimmed);
// ngModelCtrl.$render();
// Angular solution is???
input.value = trimmed;
}
最近的 angular 4 版本引入了一个新指令来处理这些情况
<input [name]="fullName" pattern="[a-zA-Z ]*" [(ngModel)]="...">
在模式中你可以指定任何正则表达式
更新:根据评论,如果您试图限制用户输入字符,您可以使用自定义指令。
为你的指令函数使用下面的代码
@HostListener('keydown') onKeydown() {
let value= this.el.nativeElement.value;
let key= value.charCodeAt(value.length -1])
let strippedString ='';
if(!((key > 64 && key < 91) || (key> 96 && key< 123) || key== 8 || key== 32 || (key>= 48 && key<= 57)){
strippedString = this.el.nativeElement.value.substring(0,value.length-1)
this.el.nativeElement.value = strippedString
}
所以我确实找到了一个解决方案,使用 NgControl
注入 private ngControl: NgControl
然后访问它的控件 属性 this.ngControl.control.patchValue(newValue);
,它更新输入字段模型我的 onKeyDown
活动中的 ReactiveForm
- 请参阅 plunker
BUT 基于智能组件和哑组件的使用 EventEmitter
实际上是一个更好的解决方案,它将值从输入 - plunker(感谢 Todd Motto 和他的 Ultimate Angular 课程)