Directive to upper case input fields
Asked Answered
N

8

9

I want to use a directive to transform all input data to uppercase. To achieve that, I create this custom directive :

@Directive({
  selector: '[appToUpperCase]'
})
export class ToUpperCaseDirective {

  constructor() {}

  @HostListener('input', ['$event']) onKeyUp(event) {
    event.target['value'] = event.target['value'].toUpperCase();
  }

}

And I use it like that :

<form [formGroup]="formGroup" appToUpperCase>

It works almost good exept that when I enter text in my field, the upper case transform is permormed but the focus is set at the end of the field...So when I edit a pre filled input, if I want to modify the begining of the data, I have to set the focus at the right place after each Keyup event...

How can I fix that ?

Nickey answered 19/10, 2017 at 7:52 Comment(0)
Y
11

For reactive form inputs (and also textareas) I got it working just with:

import { Directive, HostListener } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
  selector: '[formControlName][inputUppercase]'
})
export class InputUppercaseDirective {

  constructor(
    private readonly control: NgControl
  ) { }

  @HostListener('input', ['$event.target'])
  public onInput(input: HTMLInputElement): void {
    const caretPos = input.selectionStart;
    this.control.control.setValue(input.value.toUpperCase());
    input.setSelectionRange(caretPos, caretPos);
  }
}
Year answered 1/4, 2020 at 15:36 Comment(0)
J
10

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.

// user.component.html
<input  type="text" name="name" class="form-control" formControlName="name" uppercase />


// user.component.ts
import { Directive, ElementRef, HostListener } from '@angular/core';
@Directive({
selector: '[uppercase]',
  host: {
    '(input)': '$event'
  }
})
export class UppercaseInputDirective {

  lastValue: string;

  constructor(public ref: ElementRef) { }

  @HostListener('input', ['$event']) onInput($event) 
  {
    var start = $event.target.selectionStart;
    var end = $event.target.selectionEnd;
    $event.target.value = $event.target.value.toUpperCase();
    $event.target.setSelectionRange(start, end);
    $event.preventDefault();

    if (!this.lastValue || (this.lastValue && $event.target.value.length > 0 && this.lastValue !== $event.target.value)) {
      this.lastValue = this.ref.nativeElement.value = $event.target.value;
      // Propagation
      const evt = document.createEvent('HTMLEvents');
      evt.initEvent('input', false, true);
      event.target.dispatchEvent(evt);
    }
  }
}

I posted here in stackblitz

Juglandaceous answered 11/1, 2019 at 11:5 Comment(2)
Why you need to do this $event.target.setSelectionRange(start, end); ? Could you explain a bitEsterify
This seems nice at first, but undo does not appear to work (on Chrome 81).Groovy
D
5

Basically when you modify the value from imperative code, it becomes difficult manage position of cursor. When you re-write value input value, it throws cursor at the start of input.

I'd recommend you to go for CSS way. More cleaner

[my-attribute] input { text-transform: uppercase; }
Dobsonfly answered 19/10, 2017 at 7:55 Comment(3)
The problem is that CSS display the data in upper case but don't transform the value. I have many pages with many forms so I want a simple way to transform the incoming data to uppercase for the display and in the model. It s the reason why I used a DirectiveNickey
@JulienAZEMA I'd go with this one, you get the visual appearance and seems you have a form, so what you could do is that upon submit you can iterate the form object properties and transform them to uppercase :)Superpose
this solutions is simple and works for me ⭐⭐⭐⭐⭐Kneeland
C
1

Pankaj's idea it's better than create a directive. You only must send data.toUpperCase(). Anyway if you want use a directive like this. Be careful, not only we must use preventDefault(), we must dispatch event change

import { Directive,HostListener } from '@angular/core';

@Directive({
  selector: '[appToUpperCase]'
})
export class ToUpperCaseDirective {

  constructor() { }

  @HostListener('keydown', ['$event']) onKeyDown(event:KeyboardEvent) {
    if (event.keyCode>32 && event.keyCode<128)
   {
      event.target['value']+=event.key.toUpperCase();
      event.preventDefault(); //stop propagation
      //must create a "input" event, if not, there are no change in your value
      var evt = document.createEvent("HTMLEvents");
      evt.initEvent("input", false, true);
      event.target.dispatchEvent(evt);
    }

  }

}
Concoff answered 19/10, 2017 at 14:21 Comment(1)
event.keyCode>32 && event.keyCode<128 is a bad idea. If you press del, keyup etc. Check codes on this website : keycode.info I prefer use onInput event.Calva
C
0
import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[lowercaser]'
})
export class LowerCaserDirective {

  lastValue: string;

  constructor(public ref: ElementRef) {
  }

  @HostListener('input', ['$event']) onInput(event) {
    const resEventValue = event.target.value.toLowerCase();
    // Avoid max call
    if (!this.lastValue || (this.lastValue && event.target.value.length > 0 && this.lastValue !== resEventValue)) {
      this.lastValue = this.ref.nativeElement.value = resEventValue;
      // Propagation
      const evt = document.createEvent('HTMLEvents');
      evt.initEvent('input', false, true);
      event.target.dispatchEvent(evt);
    }
  }

}
Calva answered 5/11, 2018 at 14:41 Comment(1)
Works with TD form (Angular 7). Please check this deprecation on MDN about events: developer.mozilla.org/en-US/docs/Web/API/Event/initEventTutty
M
0
<input class="form-control form-control-sm" id="area" type="text" formControlName="carea" #carea (keyup)="makeUpperCase(addform.get('carea'))"


makeUpperCase(control: FormControl) {
control.setValue(control.value.toUpperCase());

}

make a function in your util.servce.ts or component.ts, take form control as an input, setValue for that control as mentioned in the code.

Call this function from your component.html as shown.

Morehead answered 25/10, 2021 at 12:52 Comment(0)
P
0

Upgrading @Leasye answer due to the deprecation of initEvent as mentioned by @robert I have used Event class to create the event. I've also used setProperty() method of Renderer2 to assign value to input element, rather than assigning it to the DOM object directly.

import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';

@Directive({
  selector: '[appTextUppercase]'
})
export class TextUppercaseDirective {
  preValue: string = "";

  constructor(private elmRef: ElementRef, private renderer: Renderer2) { }

  @HostListener('input', ['$event']) onInput(event: any) {
    const text_upper = event.target.value.toUpperCase();
    if (!this.preValue || (this.preValue && text_upper && this.preValue !== text_upper)) {
      this.preValue = text_upper;
      this.renderer.setProperty(this.elmRef.nativeElement, 'value', text_upper);
      const htmlEvent = new Event('input', { "bubbles": false, "cancelable": true         
    });
        document.dispatchEvent(htmlEvent);
        }
    };
}

However, would like to point to an issue in the above directive, that it does not bind the last edited character in case of editing the field value by moving the cursor back. In which case solution by @Andy works fine.

Pipes answered 10/2, 2022 at 15:34 Comment(0)
C
0

Upgrading @Amit answer to solve issue, that directive does not bind the last edited character, you can use target.dispatchEvent(htmlEvent) instead of document.dispatchEvent(htmlEvent). It helped me to solve this problem.

Collision answered 13/12, 2022 at 11:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.