Angular Async Validation


I recently posted about Angular 2 Form validation which didn’t cover asynchronous validation. This post does cover an async validation example …

I’ve put all the classes in the same file to make the example simpler to show and read. The example gives a textbox for the user to enter a product code and validates that the product code exists and puts a description at the side if it does.

Referencing an async validator in FormBuilder

The first key point is that you reference the async validator in the 3rd parameter in FormBuilder.group(). None async validators go in the 2nd parameter - I only have a async validator in my example.

constructor(builder: FormBuilder) {
this.orderForm = builder.group({
productCode: ["", , ProductValidator.productExists]
});
}

Writing the async validator

The async validator needs to return a promise that in turn returns null if valid or something else if not valid. In this example, I am calling a ProductService class to check whether the product exists

class ProductValidator {
static productExists(control: Control): { [key: string]: any } {
return new Promise(resolve => {
var productService = new ProductService();
var product: Product;
productService.getProduct(control.value).then(productFound => {
if (productFound == null) {
// need to return something if not ok
resolve({ productExists: false });
} else {
// need to return null if ok
resolve(null);
}
});
});
}
}

Here’s the full listing …

import { Component } from "angular2/core";
import {
FORM_DIRECTIVES,
Control,
ControlGroup,
FormBuilder,
Validators
} from "angular2/common";
class Product {
code: string;
description: string;
}
class ProductService {
public getProduct(productCode: string): Promise<Product> {
return new Promise(resolve => {
// simulate a call to a web api with a setTimeout()
setTimeout(() => {
// pretent these are our products in our database
var products: Product[] = [
{ code: "P001", description: "Chai" },
{ code: "P002", description: "Tofu" },
{ code: "P003", description: "Pavlova" }
];
// this is the product code we want to check exists
var productCodeToCheck: string = productCode;
// check if the product code exists
var foundProduct: Product;
products.forEach(function(product: Product) {
if (productCodeToCheck === product.code) {
foundProduct = product;
}
});
resolve(foundProduct);
}, 1000);
});
}
}
class ProductValidator {
static productExists(control: Control): { [key: string]: any } {
return new Promise(resolve => {
var productService = new ProductService();
var product: Product;
productService.getProduct(control.value).then(productFound => {
if (productFound == null) {
// need to return something if not ok
resolve({ productExists: false });
} else {
// need to return null if ok
resolve(null);
}
});
});
}
}
@Component({
selector: "my-app",
template: `
<form [ngFormModel]="orderForm">
<div>
<input
#productCode
type="text"
placeholder="product code"
ngControl="productCode"
(keyup)="lookupDescription(productCode.value)"
/>
<span>{{ productDescription }}</span>
</div>
</form>
`,
styles: [
`
.ng-invalid {
border-left: 5px solid #a94442;
}
`
],
directives: [FORM_DIRECTIVES]
})
export class AppComponent {
public productDescription: string;
orderForm: ControlGroup;
constructor(builder: FormBuilder) {
this.orderForm = builder.group({
productCode: ["", , ProductValidator.productExists]
});
}
lookupDescription(productCode) {
// initialise the description before we lookup the description
this.productDescription = "";
// call a service to lookup the description
var productService = new ProductService();
var product: Product;
productService.getProduct(productCode).then(productFound => {
if (productFound) {
// set the components productDescription which will automatically show in the UI
this.productDescription = productFound.description;
}
});
}
}

Learn React with TypeScript - 3rd Edition

New

A comprehensive guide to building modern React applications with TypeScript. Learn best practices, advanced patterns, and real-world development techniques.

View on Amazon
Learn React with TypeScript - Third Edition