How to convert input value to uppercase in angular 2 (value passing to ngControl)
Asked Answered
E

10

30

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.

Elsworth answered 6/3, 2016 at 11:29 Comment(7)
would you please show us some code or what have you done so far?Afeard
<input type="text" #input [value]="input.value.toUpperCase()" />Yoko
have you done with the answer?Afeard
possibly consider using CSS. text-transform:uppercase; to make it uppercase?Ringsmuth
FYI: text-transform: uppercase also affects the placeholder of the inputButtermilk
@Ringsmuth the css class will only affect the visual appearance , not the actual value.Aeneous
I would definitely use reactive forms and in the component subscribe to valueChanges events for the form field, and in the subscribe handle modification of form values.Dakota
B
39

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

Biarritz answered 6/3, 2016 at 16:43 Comment(9)
This will give an error if implemented in beta 9. 'Value changed after it was last checked'Karlotta
I still get it. I've fixed it by not doing it at all since (ngModelChange) doesn't work either.Karlotta
Are you sure it's the above code that's causing the issue? I'm not getting any errorsBiarritz
this line doesn't work: <input type="text" #input (input)="input.value=$event.target.value.toUpperCase()" />Karlotta
Seems to work fine. Here is a plnkr: plnkr.co/edit/uq6qxHHVxOl3M0aVCCBG?p=previewBiarritz
It also works with double binding great: plnkr.co/edit/EmfpsND4q1ozsPQ6wene?p=previewEtiquette
I attempted the first method in an [(ngModel)] template type form and the last character is not upperCased, despite the value being visually uppercase in the input field (document.getElement...().value shows the true value). There are no other dynamic input or onChange handlers. Using angular2/[email protected].Stamen
it's working for me. Thanx. whatever I enter in the text box has to change as upper case. it'w working Angular CLI projects. May be you missed import { FormControl } from '@angular/forms' ur compoents.Emptyheaded
input.value=$event.target.value.toUpperCase()" in this implementation if the last character is in lowercase. it remains as it is. angular 4.3Harbour
F
25

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/>
Foe answered 28/6, 2017 at 11:45 Comment(8)
Simple, elegant, effective, no hassles. The order of the selectors does not matter, so they can be reversed if you need to comply with TS linting against Angular standards. This should be the accepted answer IMO. Well done!Levi
Worked like charm with reactive form .Ferrick
Mine didn't work, what did I forget? 1) created the class, 2) imported on my SharedModule.ts, 3) imported SharedModule.ts on MyPage.ts and set the field just like in the example above.Frissell
@franzisk_br Did you export the directive from SharedModule?Foe
how does this.value bind with the data in the form? I don't see where that happensExcepting
the last character it's lowercased, how can i fix this? (i'm using angular 6)Tenancy
I developed a solution in Angular 7 for uppercase and lowercase, based in some posts i've read. But i tested only for reactive forms. This solution resolve the problem of the last word and the position of the cursor. stackblitz.com/edit/angular-form-uppercase-lowercaseTenancy
@Foe if we are intercepting input event on the host, should we be <!-- language: lang-ts --> $event.preventDefault(); $event.stopPropagation(); ?Dilapidate
S
12
<input type="text" oninput="this.value = this.value.toUpperCase()">
works good in angular to get every symbol to be a big one :)
Storiette answered 5/9, 2019 at 20:26 Comment(1)
Is this compatible with all devices with latest browsers?Impetrate
L
9

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):

Lobachevsky answered 6/3, 2016 at 13:28 Comment(2)
In order to to make it work with validation ([class.invalid]="myControl.touched && !myControl.valid), in response to the input event I needed to call super.writeValue(updatedValue); this.onTouched(); this.onChange(updatedValue);Cetacean
DefaultValueAccessor source as of 4.3.2Combo
C
9

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>
Combo answered 2/8, 2017 at 0:10 Comment(4)
I was happy to find Your solution @Combo but I do not get it to work in combination with the [formControlName] directive on the same input element. Have you gotten that to work?Trine
Glad it helps somehow. Yes it does work, just added an usage example. Just double checking: did you actually add directive to the list of declared and/or exported components in some module?Combo
@Combo I used your approach in Angular 8, I could not use host binding in decorator, so I used host listener instead, it worked like a charm :) on a side note, if we use a host listener to capture input event, should we stop propagation and prevent default $event.preventDefault(); $event.stopPropagation();Dilapidate
Sorry I cannot help on this, I've been far from this specific bit of angular for some timeCombo
T
5

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.

Tungusic answered 24/7, 2017 at 8:51 Comment(1)
tested with both reactive and template-driven forms, works OK!Catenoid
D
2

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!

Dragonfly answered 16/2, 2019 at 22:55 Comment(0)
I
2

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()">
Ics answered 8/4, 2020 at 21:23 Comment(1)
Clean and simple. Like it.Flunky
D
1

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 }

}
Distasteful answered 10/3, 2017 at 22:2 Comment(1)
It seems to me that a lot of pieces are just the same as DefaultAccessor. Why not inherithing from that, and adding only what's different?Combo
C
0

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>
Clutch answered 25/7, 2018 at 7:51 Comment(3)
This works great, but there is one small issue if I have this on template driven form once I submit the form I get the value all uppercase except the last character. So if I type: 'aaa' this directive does the transformation to 'AAA' but once I submit I got the value as 'AAa' <- last letter is not transformed. Any Idea? (Angular 6)Plasm
@Plasm did you fix it?Avaria
@AlexanderRojas This looks promising: https://mcmap.net/q/394375/-directive-to-upper-case-input-fieldsPlasm

© 2022 - 2024 — McMap. All rights reserved.