Improve your way to validate angular reactive forms
Tags: angular, rxweb
Published: 2019-06-25 10:36:00

When it to comes to large data oriented forms, complexity increases while validating the controls and so it becomes necessary to use a better and efficient approach to validate them.  

One of the most efficient approach is decorator based validation, the benefit of using it is you can use model based strategy to construct angular reactive forms in which you just need to add a decorator `@alpha()`,`@required()` on the class property, you don't need to add any extra code in HTML or create any custom validation function in the component 

Let's make it happen in a few steps:

1) Install [@rxweb/reactive-form-validators](https://www.npmjs.com/package/@rxweb/reactive-form-validators)

> npm install [@rxweb/reactive-form-validators](https://www.npmjs.com/package/@rxweb/reactive-form-validators)

2) You also need import `RxReactiveFormsModule` in the app.module.

  ```js
  import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { FormsModule,ReactiveFormsModule } from '@angular/forms';

  import { AppComponent } from './app.component';

  import {  RxReactiveFormsModule } from "@rxweb/reactive-form-validators"
  @NgModule({
  imports:      [ BrowserModule, 
  FormsModule,ReactiveFormsModule,RxReactiveFormsModule ],
  declarations: [AppComponent],
  bootstrap:    [ AppComponent]
  })
  export class AppModule { }
```

3) Create User Model:
Let's create a user model class and create properties like firstName, lastName and username, password and confirmPassword into it and pass the respective validation decorators. 

```js
import { required, compare, alpha, minLength } from "@rxweb/reactive-form-validators";

export class User {

@required()
firstName:string;

@required()
lastName:string;

@required()
@alpha()
userName:string;

@required()
@minLength({value:8})
password:string;

@required()
@compare({fieldName:'password'})
confirmPassword:string;

}
```

4) Create user component:
Now, Let's create a user component for building the reactive form based upon our model class. for that you need to import `RxFormBuilder` and create the formGroup object with the use of the user model class.

```js
import { Component, OnInit } from '@angular/core';
import { FormGroup } from "@angular/forms"
import { RxFormBuilder } from '@rxweb/reactive-form-validators';
import { User } from './user.model';
@Component({
selector: 'app-user',
templateUrl: './user.component.html'
})
export class UserComponent implements OnInit {
userFormGroup: FormGroup 
constructor(
private formBuilder: RxFormBuilder 
) { }
  ngOnInit() 
  {
  let user = new User();
  this.userFormGroup = this.formBuilder.formGroup(user); 
}
} 
```
5) Create user form:
Create a user form and inside the `formGroup` element define all the properties as formControl

```js
<h1 class="bd-title" id="content">User Registration Form</h1>
<br/>
<form *ngIf="userFormGroup" [formGroup]="userFormGroup">
<div class="form-group">
<label>First Name</label>
<input type="text" formControlName="firstName" class="form-control" />
<small class="form-text text-danger" *ngIf="userFormGroup.controls.firstName.errors">{{userFormGroup.controls.firstName.errors.required.message}}<br/></small>
</div>
<div class="form-group">
<label>Last Name</label>
<input type="text" formControlName="lastName" class="form-control" />
<small class="form-text text-danger" *ngIf="userFormGroup.controls.lastName.errors">{{userFormGroup.controls.lastName.errors.required.message}}<br/></small>
</div>
<div class="form-group">
<label>User Name</label>
<input type="text" formControlName="userName" class="form-control" />
<small class="form-text text-danger" *ngIf="userFormGroup.controls.userName.errors && userFormGroup.controls.userName.errors.required">{{userRegistrationFormGroup.controls.userName.errors.required.message}}<br/></small>
<small class="form-text text-danger" *ngIf="userFormGroup.controls.userName.errors && userFormGroup.controls.userName.errors.alpha">{{userFormGroup.controls.userName.errors.alpha.message}}<br/></small>
</div>
<div class="form-group">
<label>Password</label>
<input type="password" formControlName="password" class="form-control" />
<small class="form-text text-danger" *ngIf="userFormGroup.controls.password.errors && userFormGroup.controls.password.errors.required">{{userFormGroup.controls.password.errors.required.message}}</small>
<small class="form-text text-danger" *ngIf="userFormGroup.controls.password.errors && userFormGroup.controls.password.errors.minLength">{{userFormGroup.controls.password.errors.minLength.message}}<br/></small>
</div>
<div class="form-group">
<label>Confirm Password</label>
<input type="password" formControlName="confirmPassword" class="form-control" />
<small class="form-text text-danger" *ngIf="userFormGroup.controls.confirmPassword.errors && userFormGroup.controls.confirmPassword.errors.compare">{{userFormGroup.controls.confirmPassword.errors.compare.message}}<br/></small>
</div>
<button [disabled]="!userFormGroup.valid" class="btn btn-primary">Submit</button>
</form>
```

6) Configure validation messages globally

For displaying the validation messages if the `formControl` becomes invalid. you need to configure it globally in app component

You have to use `ReactiveFormConfig` class set method and pass the validation message object.

```js
ReactiveFormConfig.set({
  "validationMessage": {
     "required": "This field is required.",
     "minLenght":"Enter minimum length of {{0}} characters.",
     "compare":"The value should be matched with {{0}}.",
     "alpha":"you can only enter alphabets."
}
});
```
Please refer the [working example code]
(https://stackblitz.com/edit/rxweb-reactive-form-validation-angular-user-registration-7fh1vv?file=src/app/app.component.ts)

Other benefits to use this approach:
### Conditional validation :

In some of the cases you may require your validation to be fired based upon some condition. To implement it using decorator based approach you must pass parameter `conditionalExpression` in the decorator above the property. 

```js
import {required} from "@rxweb/reactive-form-validators"

export class User{

  @required()  
  firstName:string;

  @required({conditionalExpressions:(x=>x.firstName == "John")})
  lastName:string;

}  
```
Please refer the [working example](https://stackblitz.com/edit/rxweb-reactive-form-validation-angular-user-registration-fyy96m)

### Show Custom Message :

If you want to show a custom validation message on a particular field, You must pass it in `message` parameter in the decorator above the property. 

```js
import {required} from "@rxweb/reactive-form-validators"

export class User{

  @required()  
  firstName:string;

  @required({message:"Last Name is required"})
  lastName:string;

}
```
Please refer the [working example](https://stackblitz.com/edit/rxweb-reactive-form-validation-angular-user-registration-dcfngp)

This validation framework has several other validators which can be used directly in component without creating custom validation functions
 
If you have any question/suggestion, Please share your comments below.