Skip to content

Instantly share code, notes, and snippets.

@FFKL
Created September 16, 2021 14:04

Revisions

  1. FFKL created this gist Sep 16, 2021.
    57 changes: 57 additions & 0 deletions input-transform.directive.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    import { Directive, ElementRef, HostListener, Input, Renderer2 } from '@angular/core';
    import { ControlValueAccessor } from '@angular/forms';

    export function valueAccessor<T extends new (...args: any[]) => any>(component: T) {
    return {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => component),
    multi: true
    };
    }

    export type TransformFn = (value: any) => any;

    @Directive({
    selector: 'input[type=text][formControlName][appInputTransform],textarea[formControlName][appInputTransform],input[type=text][formControl][appInputTransform],textarea[formControl][appInputTransform],input[type=text][ngModel][appInputTransform],textarea[ngModel][appInputTransform]',
    providers: [valueAccessor(InputTransformDirective)]
    })
    export class InputTransformDirective implements ControlValueAccessor {
    @Input('appInputTransform') transform: TransformFn = val => val;

    onChange = (_: any) => { };

    @HostListener('blur') onTouched = () => { };

    constructor(
    private readonly renderer: Renderer2,
    private readonly elementRef: ElementRef
    ) { }

    @HostListener('input', ['$event.target.value'])
    handleInput(value: any): void {
    const transformedValue = this.transform(value);
    this.onChange(transformedValue);
    this.setProperty('value', transformedValue);
    }

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

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

    writeValue(value: any): void {
    const normalizedValue = value == null ? '' : value;
    this.setProperty('value', normalizedValue);
    }

    setDisabledState(isDisabled: boolean): void {
    this.setProperty('disabled', isDisabled);
    }

    private setProperty(key: string, value: any): void {
    this.renderer.setProperty(this.elementRef.nativeElement, key, value);
    }
    }