简体   繁体   中英

Directive to upper case input fields

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?

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

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

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

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

  }

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

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


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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM