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