Reuní una directiva de atributo de moneda en un FormControl ReactiveForm que usa @HostListener en un evento de entrada (onKeyDown) para eliminar todos los caracteres no válidos (letras y símbolos) a medida que se escriben en la entrada, pero permite números y decimales. PERO , si escribe un carácter no válido (es decir, a ) en un campo de entrada vacío y la directiva lo elimina, el modelo no se actualiza.
He agregado una configuración de plunker usando la directiva de moneda. Pasos a seguir para entender mi pregunta:
123a , no obtiene una a en la entrada porque no se permiten letras, y el botón está deshabilitado porque el formulario no es válido (bien)123.456 no obtiene un 6 en la entrada ya que solo se permiten 2 decimales, y el botón está deshabilitado ya que el formulario no es válido (bueno)a , no obtiene una a en la entrada, PERO el trasero está habilitado ya que el modelo cree que tiene a a aunque la interfaz de usuario no lo muestre (malo) Puede verificar que el modelo no se actualice haciendo clic en el botón y mirando en la consola, que registra this.form.value y muestra { amount: 'a' } . Si escribe un carácter válido a continuación, el modelo solo contendrá ese a y se habrá eliminado. Entonces, solo en este caso, el modelo no se actualiza correctamente.
Este fue un problema que se resolvió fácilmente en AngularJS usando ngModel validator and parser pipes , modelValue , $setViewValue y $render() para actualizar y forzar a AngularJS a ejecutar $digest. ¿Cómo haces esto en Angular?
Este es un fragmento de mi directiva de atributos que elimina los caracteres no deseados con éxito:
@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(/\.([^\.]*)$/, '$1'); } // 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; }Así que encontré una solución para esto usando NgControl donde inyecté private ngControl: NgControl luego accedió a su propiedad de control this.ngControl.control.patchValue(newValue); , que actualiza el modelo de campos de entrada en un ReactiveForm en mi evento onKeyDown - ver plunker
PERO basado en el uso de componentes inteligentes y tontos, el uso de un EventEmitter es en realidad una mejor solución que pasa el valor al formulario principal desde la entrada: plunker (gracias a Todd Motto y sus cursos Ultimate Angular)
Con el reciente lanzamiento de angular 4, se introduce una nueva directiva para manejar estos escenarios
<input [name]="fullName" pattern="[a-zA-Z ]*" [(ngModel)]="...">en el patrón puede especificar cualquier expresión regular
Actualización: según el comentario, si está tratando de restringir que el usuario ingrese caracteres, puede usar la Directiva personalizada.
Use el siguiente código para su función de directiva
@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 }