Search code examples
angularangular-directiveangular-formshtml-inputangular-validation

Angular custom directive not working on input pattern


I'm trying to set a regex pattern with a custom Angular directive:

import { Directive, ElementRef } from '@angular/core';

@Directive({
  selector: '[appPasswordRegex]',
})
export class PasswordRegexDirective {
  constructor(private el: ElementRef) {
    this.el.nativeElement.pattern = '^(?=.*?[a-zA-Z])(?=.*?[0-9]).*$';
  }
}

HTML:

<input
      appPasswordRegex
      type="password"
      ngModel
      name="password"
      required
      minlength="7"
    />

I also check this.el in console and pattern property is changed successfully, but it isn't applied in action. Contrary to this, if I just write the pattern inside an input like this below, it works perfectly, even though pattern property is being changed in both cases:

<input
      type="password"
      ngModel
      name="password"
      required
      pattern="^(?=.*?[a-zA-Z])(?=.*?[0-9]).*$"
      minlength="7"
    />

what could be the issue?


Solution

  • When you add a pattern directly to an input that has ngModel, you're not just setting the attribute. In the FormsModule there's a PatternValidator directive that matches that selector and adds the validation around the pattern supplied to the ngModel's FormControl.

    To achieve a similar behavior with your directive, you must create a custom validator directive. Here you can find the official documentation on how to create them.

    As an example you could do something like this:

    @Directive({
      selector: '[appPasswordRegex]',
      providers: [
        {
          provide: NG_VALIDATORS,
          useExisting: PasswordRegexDirective,
          multi: true,
        },
      ],
    })
    export class PasswordRegexDirective implements Validator {
      validate(control: AbstractControl): ValidationErrors {
        return /^(?=.*?[a-zA-Z])(?=.*?[0-9]).*$/.test(control.value)
          ? null
          : { invalidPassword: true };
      }
    }
    

    cheers