简体   繁体   中英

Error message for multiple validator.pattern Angular 7

I have a reactive form using angular 7 and each field has more than one pattern to validate. I want to make an error message for each pattern but I can't find a way to identify them.

In my Ts file I have something like this:

myfield: ['', [ //Validators.pattern(/^/), Validators.pattern(/^/), Validators.pattern(/^/)]],

And in my html file;

<p class="error" *ngIf="myFormGroup.get('myField').hasError('pattern')"> pattern error</p>

I want to be able to separate each one of my patterns to show the appropiate error message Something like:

<p class="error" *ngIf="myFormGroup.get('myField').hasError('pattern1')"> pattern error 1</p>

<p class="error" *ngIf="myFormGroup.get('myField').hasError('pattern2')"> pattern error 2</p>

Any thoughts about this? My form has many fields, validators and components. So I am looking for a simple way.

the pattern validator returns the violated pattern in it's ValidationErrors object. so you could possibly leverage that like this:

<p class="error" *ngIf="myFormGroup.get('myField').errors?.pattern">
  <ng-container *ngIf="myFormGroup.get('myField').errors.pattern.requiredPattern === pattern1">Pattern 1 Error</ng-container>   
   <ng-container *ngIf="myFormGroup.get('myField').errors.pattern.requiredPattern === pattern2">Pattern 2 Error</ng-container>
</p>

and so on. A limitation here is that it will only return one violated pattern at a time due to the nature of the errors object being a keyed object that can only have one pattern violation at a time. If you need to display multiple pattern errors at once, then you will need a custom validator that supports multiple patterns.

You need custom validators ( https://angular.io/guide/form-validation#custom-validators ):

export function customValidator(): ValidatorFn {
  return (control: AbstractControl): { [key: string]: {message: string} } | null => {

    if (!new Regexp(/regexpPattern1Here/).test(control.value)) {
      return {
        pattern1Error: {
          message: `Error message for pattern 1`
        }
      };
    } 

    if (!new Regexp(/regexpPattern2Here/).test(control.value)) {
      return {
        pattern2Error: {
          message: `Error message for pattern 2`
        }
      };
    } 

   return null;
  };
}

And instead of doing

myfield: ['', [
        //Validators.pattern(/^/),
        Validators.pattern(/^/),
        Validators.pattern(/^/)]],

, do

myfield: ['', [customValidator()]],

Update @bryan66 's asnwer

Due too the "Suggested edit queue is full" for this answer I felt we need a more contemporary answer for 2022. So here is updated answer:

First of we need to fix our component's class

@Component({
  selector: 'app-component-name',
  templateUrl: './component-name.component.html',
  styleUrls: ['./component-name.component.css'],
})
export class ComponentName implements OnInit {
  public loginForm: FormGroup;
  public passwordSpecialChar = '!@#$&*';
  public passwordShouldContainsSpecialChar = /(?=.*[!@#$&*])/;
  public passwordShouldContainsOneLowercaseLetter = /(?=.*[a-z])/;
  
  constructor(private formBuilder: FormBuilder) {}

  ngOnInit(): void {
    this.loginForm = this.formBuilder.group({
      password: [
        '',
        Validators.compose([
          Validators.minLength(8),
          Validators.required,
          Validators.pattern(this.passwordShouldContainsSpecialChar),
          Validators.pattern(
            this.passwordShouldContainsOneLowercaseLetter,
          ),
        ]),
      ],
    });
  }
}

And our template would be like this:

<div
  *ngIf="
    loginForm.get('password').invalid &&
    (loginForm.get('password').touched ||
    loginForm.get('password').dirty)
"
>
  <ul>
    <li
      class="text-danger"
      *ngIf="loginForm.get('password').hasError('required')"
    >
      Please enter your password
    </li>
    <li
      class="text-danger"
      *ngIf="loginForm.get('password').hasError('minlength')"
    >
      Password should be at least {{
      loginForm.get('password').errors['minlength'] .requiredLength }}
      characters.
    </li>
    <li
      class="text-danger"
      *ngIf="
        loginForm.get('password').errors['pattern']
        .requiredPattern ===
        passwordShouldContainsSpecialChar.toString()
    "
    >
      Password should contains {{ passwordSpecialChar }}
    </li>
    <li
      class="text-danger"
      *ngIf="
        loginForm.get('password').errors['pattern']
        ?.requiredPattern ===
        passwordShouldContainsOneLowercaseLetter.toString()
    "
    >
      Password should contains at least one lowercase letter
    </li>
  </ul>
</div>

Disclaimer

I still have problems with this, If user use backspace and you check more than two pattern it starts showing wrong messages or showing nothing. BTW if you could fix it please edit my message.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM