0

I did create a directive which prevents any character to be typed in an input if it doesn't match a given pattern.

import { Directive, Input, Output, HostListener, EventEmitter } from "@angular/core"


@Directive({
 selector: '[ngModel][typingPattern]'
})

export class TypingPatternDirective  {

 @Input() typingPattern: string
 @Input() ngModel
 @Output() ngModelChange = new EventEmitter()
 @Input() global: boolean = true // Global modifier
 private oldValue: any

 /* On key down, we record the old value */
 @HostListener('keydown', ['$event'])
 onKeyDown($event) {
   this.oldValue = $event.target.value
 }

 @HostListener('input', ['$event'])
 onInput($event) {
   if (!$event.target.value.match( new RegExp(this.typingPattern, this.global ? 'g' : '')) ) {
     $event.target.value = this.oldValue.trim()
   }
   this.ngModelChange.emit($event.target.value)
 }

 @HostListener('paste', ['$event'])
 onPaste($event) {
   this.onInput($event)
 }
}

And here is how I use it on a input element:

 <input type="text" [ngModel]="..." [typingPattern]="$[0-9]{0,8}^" required>

The only bug I currently have happens if in that particular example I type any characters like h. The key is gonna be prevented by my directive, but the required property is gonna considered that a character has been added and thus set the input to valid even though my ngModel value is empty and nothing is displayed. I probably need to event.preventDefault() but I am not sure where.

1
  • Why dont you use a pattern Validator instead? I know is not the case, but is an approach Commented Mar 24, 2017 at 22:33

2 Answers 2

1

I manage to get around this issue by encapsulating the this.ngModelChange.emit($event.target.value)

in a setTimeout()

by doing so, the input validation is retriggered again after, and thus the state of my input get updated correctly (the directive can thus be used correctly with required or other validators). It works for now, but it's definitely a bit hacky, and a better handler of the events should lead to a better solution.

Sign up to request clarification or add additional context in comments.

Comments

0

If i'm understanding what you're trying to do, you want to have your input filtered out by the regex passed to typingPattern. If so, then your ngModelChange EventEmitter should be emitting the 'new value' after it has been checked (and cleaned) by the RegEx. So, if the user types, in sequence: 1,2,y, then your ngModelChange should emit: 1, 12, 12.

If the above is true, then you need to capture the old value of your input BEFORE the keydown event. Then, on each keydown, if the new character is acceptable, you can ngModelChange.emit the value of your input. If, however, the new character is not acceptable, then you should emit the old value that you previously stored.

Does that make sense?

1 Comment

You are right, and that's actually what is happening. The only issue I am having is that it doesn't seem sync with other validators as let's say "required". Anything i could do about that ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.