Skip to content

Instantly share code, notes, and snippets.

@dmk1111
Last active September 17, 2018 07:35
Show Gist options
  • Select an option

  • Save dmk1111/fed68f38f05c0ce53f8ab809fa1bd0f0 to your computer and use it in GitHub Desktop.

Select an option

Save dmk1111/fed68f38f05c0ce53f8ab809fa1bd0f0 to your computer and use it in GitHub Desktop.
Example of using Angular 2+ (Angular 6) directive as input interceptor

Directives can be used as interceptors on the input before the model changes. Here is an example of such a directive:

@Directive({
	selector: '[myValueChangeInterceptor]',
	providers: [NgModel]
})
export class InputInterceptorDirective {
	@Input() public myValueChangeInterceptor: (value: string) => string;
	@Output() public valueInput: EventEmitter<string> = new EventEmitter();

	constructor(private model: NgModel, private element: ElementRef) {
	}

	@HostListener('ngModelChange', ['$event'])

	public onModelChange($event: string): void {
		const cursorPosition: number = this.element.nativeElement.selectionStart;

		if (this.myValueChangeInterceptor) {
			const newValue: string = this.myValueChangeInterceptor($event);

			this.model.valueAccessor.writeValue(newValue);
			this.valueInput.emit(newValue);

			if (newValue.length !== $event.length) {
				this.element.nativeElement.selectionStart = this.element.nativeElement.selectionEnd = cursorPosition - 1;
			}
		} else {
			this.valueInput.emit($event);
		}
	}
}

And, accordingly, the template will look something like this:

<input matInput
		   type="{{inputType}}"
		   placeholder="{{placeholder}}"
		   [ngModel]="value"
		   [myValueChangeInterceptor]="toNumericFormat"
		   (blur)="onBlur()"
		   (focus)="onFocus()"
		   (valueInput)="onValueInput($event)"
		   (keydown.enter)="onKeyDownEnter()"
		   [readonly]="disabled"
		   autocomplete="off">

and of course, with this interceptor, we can bring the string value to something that looks like number:

public toNumericFormat(value: string): string {
		const inputValue: string = value;
		let dotCount: number = 0;
		let signCount: number = 0;

		return inputValue.replace(/\D/g, (char: string) => {
			if (char === '-') {
				return (++signCount > 1 || inputValue.indexOf(char) !== 0) ? '' : char;
			}
			if (char === '.') {
				return (++dotCount > 1) ? '' : char;
			}
			return '';
		});
	}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment