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;
}
});
}
}
If you to learn more about TypeScript, you may find my free TypeScript course useful: