Logo

dev-resources.site

for different kinds of informations.

Custom Validators for Angular Reactive Forms

Published at
5/24/2020
Categories
angular
validation
forms
factory
Author
_adam_barker
Categories
4 categories in total
angular
open
validation
open
forms
open
factory
open
Author
12 person written this
_adam_barker
open
Custom Validators for Angular Reactive Forms

Angular… ugh, I know.

But Reactive Forms are actually pretty cool and once you get the hang of them, you can appreciate all of the form dynamics that Angular handles for you.

At the end of the day we want to supply an object to a form, allow the user to make changes and keep those changes valid.

Angular provides classes to marry object properties to markup and a convenient FormBuilder to help construct groups of form components with default values.

this.formGroup = formBuilder.group([
  {
    "name": [
      "Adam",
    ],
    "age": [
      "21"
    ]
  }
]);
Enter fullscreen mode Exit fullscreen mode

Out of the box Angular provides a set of validators that cover many if not most requirements.

My name should be longer than 20 characters and clearly I’m no older than 25 so I can specify validators to the FormBuilder object:

this.formGroup = formBuilder.group([
  {
    "name": [
      "Adam", Validators.maxLength(20)
    ],
    "age": [
      "21", Validators.max(25)
    ]
  }
]);
Enter fullscreen mode Exit fullscreen mode

We can check for validation errors in our FormGroup object with the errors property of each control. This property maintains an object that, when the value is valid, is empty. Otherwise, the object contains keys indicating how the value has failed validation.

For example, if our name value was say 28 characters, longer than the valid 20 characters,

formGroup.get("name").errors
Enter fullscreen mode Exit fullscreen mode

would return:

{
    maxLength: {
        actualLength: 28,
        requiredLength: 20
    }
}
Enter fullscreen mode Exit fullscreen mode

If we need something a little extra, something outside the typical min, max, required or email, we can write a custom validator.

Suppose we wanted to validate a favorite movie field. Let’s add a movie validator and determined that any value other than Back To The Future is invalid:

function movie(control: AbstractControl)
    : { [key: string]: any } {
    if (control.value !== "Back To The Future") {
        return {
          movie: {
            suppliedMovie: control.value,
            quality: "Questionable"
          }
        };
    }

    return undefined;
}
Enter fullscreen mode Exit fullscreen mode

Here we check the control’s value and it’s not the value we want we can return an object specify how the value is invalid. If the value is valid, we return undefined because we don’t want the errors object to be populated in this case.

It’s a simple change to add our new validator to the FormBuilder call:

this.formGroup = formBuilder.group({
  name: ["Adam", Validators.maxLength(25)],
  age: ["21", [Validators.min(0), Validators.max(25)]],

  // Instead of using the Validators class we can 
  // supply our own validator, movie:
  favoriteMovie: ["Silent Running", movie]
});
Enter fullscreen mode Exit fullscreen mode

What if we wanted to be less stringent and maybe offer the user of our validation function the option to specify a number of movies that could be favorites.

Now we need an argument to movie, like max and maxLength do.

function movie(
  validMovies: string[]
): ValidatorFn {
  return (control: AbstractControl): { [key: string]: any } => {
    if (validMovies.indexOf(control.value) == -1) {
      return {
        movie: {
          suppliedMovie: control.value,
          reason: "Not one of my favorites!"
        }
      };
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

Instead of the movie function now immediately validating the value and returning an error object, it’s basically a higher-order function and returning a function that Reactive Forms will use. We provide an array of movie names as an argument, and these are used by the function at validation time to check the control’s value.

this.formGroup = formBuilder.group({
  name: ["Adam", Validators.maxLength(25)],
  age: ["21", [Validators.min(0), Validators.max(25)]],

  favoriteMovie: ["Silent Running",
    movie([
        "Teen Wolf", 
        "Saving Private Ryan", 
        "Inception"
    ])]
});
Enter fullscreen mode Exit fullscreen mode

Now, Silent Running (excellent movie, criminally downvoted) is still invalid, but we’ve supplied a list of movies for which the value will be valid.

Check out the StackBlitz for this example!

factory Article's
25 articles in total
Favicon
Clojure is Awesome!!!
Favicon
Understanding the Factory and Factory Method Design Patterns
Favicon
Factory Design Pattern
Favicon
Things You Want to Ensure When Factory Resetting Your HP Laptop Without a Password
Favicon
The Factory Pattern in C#: Creating Objects the Smart Way
Favicon
Enhance Your Factory Car Radio's Bass with Affordable Upgrades
Favicon
Page Object Model and Page Factory in Selenium
Favicon
Factory functions with private variables in JavaScript
Favicon
Evoluindo nosso Projeto Rails: Integrando o Padrão Factory para Maior Flexibilidade e Organização
Favicon
Javascript Factory Design Pattern
Favicon
Dart Abstract and Factory Keywords
Favicon
Azure Data Factory Overview For Beginners
Favicon
Improve your factories in Symfony
Favicon
Reduzindo a quantidade de Branchs na criação de Objetos com uma estrutura plugável
Favicon
Java 9 Factory Method for Collections: List, Set, Map
Favicon
How to implement simple Factory Pattern in Node.js
Favicon
Factory Design Pattern (simple example implementation in PHP)
Favicon
Spring's FactoryBean Interface
Favicon
Custom Validators for Angular Reactive Forms
Favicon
Design Patterns: Factory
Favicon
Creating objects dynamically with factory pattern in javascript
Favicon
Is this the real life, is this just fantasy?
Favicon
Design Patterns: Factory Pattern, Part 2
Favicon
Patterns in Kotlin: Abstract Factory
Favicon
SUT Factory

Featured ones: