Angular ReactiveForm – Custom Validator

スポンサーリンク

Custom Validation

Angular – ReactiveForm Simple Validation explains how to use validation in Reactive Form.

For validation, I used built-in and just add them.

But, we need custom validation according to required value.

In this time, how to prepare and

Prepare custom validation function

To set custom validation, we need to prepare custom validation function which follows rule

The rule is

  • Return validation function
  • Validation function should take AbstractControl
  • Return {[key: string] : boolean} or null based on result

Return

{[key: string] : boolean} -> Error

null -> No problem

If we want to return error, we need to return key and true. If want to no error, just return null.

Let’s take a look sample validation function

formvalidationsample.component.ts

This is component code, and I just add validation function under export component

import { Validators } from '@angular/forms';
import { AbstractControl } from '@angular/forms';
import { ValidatorFn } from '@angular/forms';

// works
function nicknameValidator(c: AbstractControl): {[key : string]: boolean } | null {  
  if (c.value !== undefined && c.value === "")  {
    return {'myvalidator': true};   
  }
  return null;
}

// works
function nicknameValidator3(min: number) {
  return (c: AbstractControl):{[key: string]: boolean} | null => {
    if (c.value !== undefined && c.value === "")  {
      return {'myvalidator3': true};   
    }
    return null;
  };
}

// NG
function nicknameValidator2(): ValidatorFn {
  return (c: AbstractControl): { [key: string]: boolean } | null  => {
    if (c.value !== undefined && c.value === "")  {
       return {'myvalidator2': true}; 
    }
    return null;
  };
}


I implemented 3 ways. (But last one is not working property)

The validation is very simple.

Check input value and if this is blank, return error.

How to set custom validation function

How to use above functions? Yeah, we need to set function as validator.

import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { FormGroup } from '@angular/forms';
import { Validators } from '@angular/forms';
import { AbstractControl } from '@angular/forms';
import { ValidatorFn } from '@angular/forms';

@Component({
  selector: 'app-root',
  templateUrl: './formvalidationsample.component.html',
  styleUrls: ['./formvalidationsample.component.css']
})
export class FormvalidationsampleComponent implements OnInit {

  testForm: FormGroup;

  constructor(private fb: FormBuilder) { }

  ngOnInit(): void {
    this.testForm = this.fb.group({
      firstName: ['', [Validators.required, Validators.minLength(3)]],
      lastName: ['', [Validators.required, Validators.maxLength(50)]],
      email: ['', [Validators.required, Validators.email]],
      nickname: ['', [nicknameValidator]],
      // nickname: ['', nicknameValidator3(3)]
    });
  }

  save() {
    console.log(this.testForm);
    console.log('Saved: ' + JSON.stringify(this.testForm.value));
    console.log(this.testForm.get('nickname').errors);
  }
}

See nickname part. “nickname” 2nd parameter, = validation array has validator function, in this case use “nicknameValidator” function

If you want to use function with parameter, the function style is “nicknameValidator3”, and

Take arguments

nickname: ['', nicknameValidator3(3)]

Error detection in html template

So, validation codes are ready, but how to check from template.

To get error, use

this.testForm.get('nickname').errors?.myvalidator

The last part is validator key to return.

This is HTML codes

<h2>Home Builder Validation</h2>
<form (ngSubmit)="save()" [formGroup]="testForm">
    <input id="firstNameId" type="text"
        placeholder=""
        formControlName="firstName"
        [ngClass]="{'is-valid': (testForm.get('firstName').touched || testForm.get('firstName').dirty)
                &amp;&amp; !testForm.get('firstName').valid }"/>
    <br>

    <span class="invalid-feedback">
        <span *ngIf="testForm.get('firstName').errors?.required">
        Please enter your first name.
        </span>
        <span *ngIf="testForm.get('firstName').errors?.minlength">
        The first name must be longer than 3 characters.
        </span>
    </span>
    <br>
    <br>

    <input id="lastNameId" type="text"
        placeholder=""
        formControlName="lastName"
        [ngClass]="{'is-valid': (testForm.get('lastName').touched || testForm.get('lastName').dirty)
        &amp;&amp; !testForm.get('lastName').valid }"/>
    <br>

    <span class="invalid-feedback">
        <span *ngIf="testForm.get('lastName').errors?.required">
          Please enter your last name.
        </span>
        <span *ngIf="testForm.get('lastName').errors?.maxlength">
          The last name must be less than 50 characters.
        </span>
    </span>
    <br>
    <br>

    <input id="emailId" type="email"
        placeholder=""
        formControlName="email"
        [ngClass]="{'is-valid': (testForm.get('email').touched || testForm.get('email').dirty)}"/>
        <br>
        <br>
        <br>

    <input id="nicknameId" type="text"
        placeholder="nickname"
        formControlName="nickname"
        [ngClass]="{'is-valid': (testForm.get('nickname').touched || testForm.get('nickname').dirty) &amp;&amp; !testForm.get('nickname').valid}"/>
        <br>
    <span class="invalid-feedback">
        <span *ngIf="testForm.get('nickname').errors?.myvalidator">
            Need at least one char
        </span>
    </span>
    <br>

    <button class="btn btn-primary mr-3"
        type="submit"
        style="width:80px"
        [disabled]="!testForm.valid">Save</button>        
</form>

See span. Check whether nickname component has error or not and error type is “myvalidator” defined by key.

Result

You can see

Last part is nickname part. By default, input box is “”, and see error message. If you input something, error is dissapeared.

TypeScript
スポンサーリンク
Professional Programmer2

コメント