Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 7 - ControlValueAccessor - Trim input values that are binded to a form

We have a input field on a web page that must be trimmed at the same time as the user enter that data. As the input is binded to an Angular Form the value in the Form must also be trimmed. I use Angular 7

import {
  Directive,
  ElementRef,
  forwardRef,
  HostListener,
  Input,
  Renderer2
} from "@angular/core";
import {
  ControlValueAccessor,
  NG_VALUE_ACCESSOR
} from "@angular/forms";


@Directive({
  selector: "[ebppInputTextTrimmer]",
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => InputTextTrimmerDirective),
    multi: true
  }]
})
export class InputTextTrimmerDirective implements ControlValueAccessor {
  @Input() prevVal: string;

  @Input() isTrimEnabled: boolean;

  onChange = (_: any) => {
  }

  onTouched = () => {
  }

  constructor(
      private _renderer: Renderer2,
      private _elementRef: ElementRef) {
  }

  writeValue(value: any): void {
    const normalizedValue = value == null ? "" : value;
    this._renderer.setProperty(this._elementRef.nativeElement, "value", normalizedValue);
  }

  registerOnChange(fn: (_: any) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this._renderer.setProperty(this._elementRef.nativeElement, "disabled", isDisabled);
  }

  @HostListener("input", ["$event.target.value"])
  handleInput(inputValue: any): void {
    let valueToProcess = inputValue;
    if (this.isTrimEnabled) {
      valueToProcess = inputValue.trim();
    }

    this.onChange(valueToProcess);
    // set the value that is trimmed in the view
    this._renderer.setProperty(this._elementRef.nativeElement, "value", valueToProcess);
  }

}

The code shown works fine for me. I wonder if there a simpler solution.

like image 268
user286974 Avatar asked Sep 07 '25 17:09

user286974


1 Answers

You can create a custom value accessor like below as a directive:

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

@Directive({
  selector: 'input[trimval]',
  host: { '(keyup)': 'valOnChange($event.target)' },
  providers: [ TRIM_VAL_ACCESSOR ]
})
export class TrimValAccessor extends DefaultValueAccessor {
  onChange = (_) => {};
  onTouched = () => {};

  constructor(private renderer:Renderer) {
  }

  writeValue(value:any):void {
    if (value!=null) {
      super.writeValue(value.toString().trim());
    }
  }

  valOnChange(el) {
    let val = el.value.trim();
    this.renderer.setElementProperty(el, 'value', val);
    this.onChange(val);
  }
}

give referece in module:

declarations: [ TrimValAccessor ]

or in component like this

@Component({
  (...)
  template: `
    <input type="text" trimval/>
  `,
  directives: [ TrimValAccessor ]
})

use in input tag to trim the value

<input type="text" trimval/>
like image 90
Niraj Avatar answered Sep 09 '25 22:09

Niraj