Cómo convertir el valor de entrada a mayúscula en el angular 2 (valor que pasa a ngControl)

Estoy intentando validar los campos de entrada utilizando el valor de ngControl en angular 2. Necesito validar que el usuario ingrese siempre el valor en mayúsculas.

Ahora necesitamos convertir el valor ingresado por el usuario a mayúscula. Pero estoy manejando los valores de los campos de entrada usando ngControl, no ngModel (considerando que podría haber usado el evento ngModelChange para actualizar el valor a mayúsculas).

Entonces, ¿cuál es la mejor y más económica forma de convertir el valor utilizado por ngControl?

Como sugirió @Eric Martinez, puede crear una variable de plantilla local y enlazar la cadena en mayúscula con la propiedad del valor en el evento de entrada:

  

Alternativamente, puede hacer de esto una directiva:

 @Directive({ selector: 'input[type=text]', host: { '(input)': 'ref.nativeElement.value=$event.target.value.toUpperCase()', } }) export class UpperCaseText { constructor(private ref: ElementRef) { } } 

Para usar la directiva, especifique UpperCaseText en la lista de directivas de su componente:

 directives: [UpperCaseText] 

Demo Plnkr

Aquí está mi solución:

Usar el oyente de host para escuchar el evento de entrada y luego forzarlo a mayúsculas.

 import {Directive, EventEmitter, HostListener, Output} from '@angular/core'; @Directive({ selector: '[ngModel][uppercase]' }) export class UppercaseDirective { @Output() ngModelChange: EventEmitter = new EventEmitter(); value: any; @HostListener('input', ['$event']) onInputChange($event) { this.value = $event.target.value.toUpperCase(); this.ngModelChange.emit(this.value); } } 

Con esta directiva, puede forzar fácilmente la entrada a mayúsculas como esta:

  

Crearía una implementación personalizada de ControlValueAccessor. Esto último correspondería a una directiva que escucharía el evento de entrada del anfitrión. De esta forma, podrá poner en mayúsculas lo que llena el usuario. El control contendrá automáticamente el valor en mayúsculas.

Aquí está la implementación:

 @Directive ({ selector: 'input[uppercase]', // When the user updates the input host: { '(input)': 'onChange($event.target.value.toUpperCase())' } }) export class UppercaseValueAccessor extends DefaultValueAccessor { (...) // When the code updates the value of the // property bound to the input writeValue(value:any):void { if (value!=null) { super.writeValue(value.toUpperCase()); } } } 

No olvide registrar este progtwig de acceso de valor personalizado en los proveedores de directivas. De esta forma, se usará su acceso de valor personalizado en lugar del predeterminado.

 const UPPERCASE_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => UppercaseValueAccessor), multi: true}); @Directive ({ providers: [ UPPERCASE_VALUE_ACCESSOR ], (...) }) export class UppercaseValueAccessor ... 

Y agregue la directiva en el atributo de directivas del componente en el que desea utilizar este enfoque.

Vea esta clase para más detalles:

Este enlace podría dar pistas adicionales (ver la sección “Componente compatible con NgModel”):

Al menos en mi experiencia, encontré dos de las respuestas aquí reveladoras, pero que no funcionan por sí mismas: de Thierry Templier (también con el primer comentario), y de cal .

Reuní partes de ambos, y se me ocurrió esta versión, que ahora está trabajando con Angular 4.1.1 en forma reactiva:

 import { Directive, Renderer, ElementRef, forwardRef } from '@angular/core'; import { NG_VALUE_ACCESSOR, DefaultValueAccessor } from '@angular/forms'; const LOWERCASE_INPUT_CONTROL_VALUE_ACCESSOR = { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => LowerCaseInputDirective), multi: true, }; @Directive({ selector: 'input[lowercase]', host: { // When the user updates the input '(input)': 'onInput($event.target.value)', '(blur)': 'onTouched()', }, providers: [ LOWERCASE_INPUT_CONTROL_VALUE_ACCESSOR, ], }) export class LowerCaseInputDirective extends DefaultValueAccessor { constructor(renderer: Renderer, elementRef: ElementRef) { super(renderer, elementRef, false); } writeValue(value: any): void { const transformed = this.transformValue(value); super.writeValue(transformed); } onInput(value: any): void { const transformed = this.transformValue(value); super.writeValue(transformed); this.onChange(transformed); } private transformValue(value: any): any { const result = value && typeof value === 'string' ? value.toLowerCase() : value; return result; } } 

Esto es para minúsculas, pero todo vale también para mayúsculas, simplemente cambie el nombre de la directiva, reemplace dentro del selector y transformValue .

Editar:
Un ejemplo de uso directo del código HTML que utiliza dicha directiva:

  

pixelbits ha proporcionado una gran solución, pero no funciona en la última versión de Angular (v4.3.1) ya que las directivas se deprecian desde el componente. Mi solución se basa únicamente en su respuesta, pero funciona con la última

Estoy proporcionando una solución genérica con directiva de atributos personalizados con una entrada booleana que codificará la entrada en mayúsculas si es verdadera.

upper-case.directive.ts:

  import { Directive, ElementRef, Input } from '@angular/core'; @Directive({ selector: '[UpperCase]', host: { '(input)': 'toUpperCase($event.target.value)', } }) export class UpperCaseTextDirective { @Input('UpperCase') allowUpperCase: boolean; constructor(private ref: ElementRef) { } toUpperCase(value: any) { if (this.allowUpperCase) this.ref.nativeElement.value = value.toUpperCase(); } } 

Aquí está el componente de aplicación correspondiente con la plantilla.

aplicaciones

  //our root app component import {Component, NgModule, VERSION} from '@angular/core' import {BrowserModule} from '@angular/platform-browser' import {UpperCaseTextDirective} from './upper-case.directive' @Component({ selector: 'my-app', template: ` 

Hello {{name}}

Auto Capitalize True:
Auto Capitalize False:
`, }) export class App { name:string; allowEdit:boolean; constructor() { this.name = `Angular! v${VERSION.full}`; this.allowEdit= false; } } @NgModule({ imports: [ BrowserModule ], declarations: [ App,UpperCaseTextDirective ], bootstrap: [ App ] }) export class AppModule {}

Aquí hay un Plnkr que demuestra esto.

Aquí está mi solución más genérica que es básicamente como DefaultValueAccessor con una función de “transformador” de texto añadida. Entonces usarías

  

En su componente tiene la función en mayúscula (podría hacer otras cosas al lado de mayúsculas como implementar una máscara) …

  uppercase(value: string) { return value.toUpperCase(); } 

Directiva…

 import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms'; import { Directive, forwardRef, Input, OnChanges, SimpleChanges, Renderer, ElementRef } from '@angular/core'; import { TextMaskModule, MaskedInputDirective } from 'angular2-text-mask'; @Directive({ selector: 'input[transformer]', // When the user updates the input host: { '(input)': 'handleInput($event.target.value)', '(blur)': 'onTouched()' }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TextTransformerDirective), multi: true }, ] }) export class TextTransformerDirective implements ControlValueAccessor { private inputElement: HTMLInputElement lastValue = ""; onTouched = () => { } onChange = (_: any) => { } @Input('transformer') transformer = (v: string) => v; constructor(private renderer: Renderer, private element: ElementRef) { } handleInput(value: any) { let newVal = this.transformer(value); if (newVal != value || this.lastValue != newVal) { this.lastValue = newVal; this.renderer.setElementProperty(this.element.nativeElement, 'value', newVal); this.onChange(newVal); } } writeValue(value: any) { let normalizedValue = value == null ? '' : value; normalizedValue = this.transformer(normalizedValue); this.renderer.setElementProperty(this.element.nativeElement, 'value', normalizedValue); } registerOnChange(fn: (value: any) => any): void { this.onChange = fn } registerOnTouched(fn: () => any): void { this.onTouched = fn } } 

Aquí está mi código de trabajo, estoy usando angular4

Esta es su directiva para mayúsculas

 import { Directive, ElementRef, HostListener } from '@angular/core'; @Directive({ selector: '[appUpper]' }) export class UpperDirective { constructor(public ref: ElementRef) { } @HostListener('input', ['$event']) onInput(event) { this.ref.nativeElement.value = event.target.value.toUpperCase(); } } 

Este es su código de archivo html donde usó la directiva de mayúsculas