28
votes

I am trying to validate the input fields using ngControl's value in angular 2. i need to validate that the user enters the value in upper case always.

Now we need to convert the value entered by user to uppercase. But i am handling values from input fields using ngControl, not ngModel ( considering i could have used ngModelChange event to update value to uppercase.)

So what is the best and low cost way to convert the value used by ngControl.

10
would you please show us some code or what have you done so far? - micronyks
<input type="text" #input [value]="input.value.toUpperCase()" /> - Eric Martinez
have you done with the answer? - micronyks
possibly consider using CSS. text-transform:uppercase; to make it uppercase? - frosty
@frosty the css class will only affect the visual appearance , not the actual value. - Enrico

10 Answers

36
votes

As @Eric Martinez suggested, you can create a local template variable, and bind the uppercase string to the value property on the input event:

<input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" />

Alternatively, you can make this a directive:

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

})
export class UpperCaseText {
    constructor(private ref: ElementRef) {
    }
}

To use the directive, specify UpperCaseText in your component's list of directives:

directives: [UpperCaseText]

Demo Plnkr

24
votes

Here is my solution:

Using host listener to listen input event and then force it to uppercase.

import {Directive, EventEmitter, HostListener, Output} from '@angular/core';
@Directive({
  selector: '[ngModel][uppercase]'
})
export class UppercaseDirective {
  @Output() ngModelChange: EventEmitter<any> = new EventEmitter();
  value: any;

  @HostListener('input', ['$event']) onInputChange($event) {
    this.value = $event.target.value.toUpperCase();
    this.ngModelChange.emit(this.value);
  }
}

With this directive, you can easily force input to uppercase like this:

<input type="text" class="form-control" placeholder="ID"
           formControlName="id" [(ngModel)]="form.value.id" uppercase/>
8
votes

I would create a custom implementation of ControlValueAccessor. The latter would correspond to a directive that would listen the input event of the host. This way you will be able to put in uppercase what you user fills. The control will automatically contains the value in uppercase.

Here is the implementation:

@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());
    }
  }
}

Don't forget to register this custom value accessor in the directive providers. This way your custom value accessor will be used instead of the default one.

const UPPERCASE_VALUE_ACCESSOR = new Provider(NG_VALUE_ACCESSOR, { useExisting: forwardRef(() => UppercaseValueAccessor), multi: true});

@Directive ({
  providers: [ UPPERCASE_VALUE_ACCESSOR ],
  (...)
})
export class UppercaseValueAccessor ...

And add the directive in the directives attribute of the component where you want to use this approach.

See this class for more details:

This link could give additional hints (see section "NgModel-compatible component):

8
votes

At least in my experience, I found two of the answers here insightful, but not working on their own: from Thierry Templier (with first comment as well), and from cal.

I put together parts of both, and came up with this version, which is now working with Angular 4.1.1 in a reactive form:

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;
  }
}

This is for lower-case, but everything holds for upper-case as well, just rename directive, replace within selector and transformValue.

Edit:
A straightforward usage example from HTML code using such directive:

<input id="myField"
       formControlName="myField"
       type="text" class="form-control required" 
       lowercase>
7
votes
<input type="text" oninput="this.value = this.value.toUpperCase()">
works good in angular to get every symbol to be a big one :)
5
votes

pixelbits has provided a great solution but it does not work in the latest version of Angular (v4.3.1) as directives are depreciated from component. My solution is based on his answer only but works with the latest

I am providing a generic solution with custom attribute directive with a boolean input which will covert the input to Uppercase if it is true.

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();
    }

    }

Here is the corresponding App component with the template.

app.ts

    //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: `
    <div>
      <h2>Hello {{name}}</h2>
      Auto Capitalize True: <input [UpperCase]="true" type="text" #input />
    <br/>
     Auto Capitalize False: <input [UpperCase]="allowEdit" type="text"/>

    </div>
    `,
    })
    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 {}

Here is a Plnkr which demonstrate this.

2
votes

In the blur event from your input text will changes the value to uppercase

<input type="text" id="firstName" name="firstName" (blur)="$event.target.value = $event.target.value.toUpperCase()">
1
votes

Here's my more generic solution which is basically like DefaultValueAccessor with a text "transformer" function added. So you would use

<input mdInput [transformer]="uppercase" ...>

In your compontent you have the uppercase function (you could do other things beside uppercase like implement a mask)...

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

Directive...

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 }

}
1
votes

Simple code without directives

In the blur event from your Input text call a method that changes the value to upper case, mine is called "cambiaUpper"

<input id="shortsel" type="text" class="form-control m-b-12" #shortsel="ngModel" name="shortsel" [(ngModel)]="_stockprod.shortName" (blur)="cambiaUpper($event)"/>

And in the component (yourComponentFile.ts) create this method that receives the event, get the value from the event and change this to uppercase.

public cambiaUpper(event: any) {
      event.target.value = event.target.value.toUpperCase();
}

Tada!

0
votes

Here is my working code i am using angular4

This is your directive for upper case

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();
  }

}

This is your html file code where you used uppercase directive

<input type="text" id="id" placeholder="id" tabindex="0" formControlName="id" appUpper>