Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 Directive to set input field to uppercase using ngModelChange

Please help. I'm having trouble creating a directive that will always set text inputs to uppercase. It seems to be working looking at the user interface but the model binding is showing the last typed character to still in lowercase character.

below is a portion of my html:

<div>
    <md-input-container fxFlex>
        <textarea #listCode mdInput [(ngModel)]="listInfo.code" placeholder="List Code" 
                  uppercase-code maxlength="50" rows="3"
                  required></textarea>
        <md-hint align="end">{{listCode.value.length}} / 50</md-hint>
    </md-input-container>
    {{listInfo.code}}
</div>

below is the directive:

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

@Directive({
  selector: '[ngModel][uppercase-code]',
  host: {
    '(ngModelChange)': 'ngOnChanges($event)'
  }
})
export class UppercaseCodeDirective {
  constructor(public model: NgControl) {}
  ngOnChanges(event) {
    var newVal = event.replace(/[^A-Za-z0-9_]*/g, '');
    newVal = newVal.toUpperCase();
    this.model.valueAccessor.writeValue(newVal);       
  }
}
like image 710
JR S. Avatar asked Jun 10 '17 01:06

JR S.


2 Answers

You should be using a directive as below,

@HostListener('keyup') onKeyUp() {
      this.el.nativeElement.value = this.el.nativeElement.value.toUpperCase();

    }

LIVE DEMO

like image 128
Aravind Avatar answered Sep 19 '22 04:09

Aravind


This question has somehow already been answered on SO, here, although solutions piled up together with framework newer versions.

At least in my experience, there were two useful answers, which on their own did not work, anyway: 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.

like image 32
superjos Avatar answered Sep 21 '22 04:09

superjos