Intuitive Decorators of RxWeb for Angular Reactive Forms
In this article, we discuss rxweb decorators, which help us to reduce the HTML template code and make our code more readable; likewise:
- Show error messages conditionally.
- Disabling FormControl conditionally without subscribing any FormControl ValueChanges,
- Conditionally assign a class on the element.
If you are unaware about the decorator-based validation in reactive forms using RxWeb, then I would suggest referring to this good article Decorator based reactive forms in Angular — An efficient way to validate forms
Import the decorator after Installing @rxweb/reactive-form-validators, after installing import
RxReactiveFormsModule
in the main module of the angular project
@disable
We come accross a lot of cases where we need to disable a control conditionally, In other words disable a control based upon other input's value. In this case the field of License Number becomes abled only when the age is greater than equal to 18
Stackblitz Example : Open
This is achieved using the following steps
1) user.model.ts:
import { disable, prop } from "@rxweb/reactive-form-validators";
import { AbstractControl } from "@angular/forms";
export class User {
@prop()
age: number;
@disable({
conditionalExpression: function(control: AbstractControl) {
return this.age <= 18 ? true : false;
}
})
@prop()
licenseNumber: string;
}
2) user.component.ts:
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-add',
templateUrl: './user-add.component.html'
})
export class UserAddComponent implements OnInit {
userFormGroup: FormGroup;
constructor(private formBuilder: RxFormBuilder) { }
ngOnInit() {
let user = new User();
this.userFormGroup = this.formBuilder.formGroup(user);
}
}
3) user.component.html:
<form *ngIf="userFormGroup" [formGroup]="userFormGroup">
<div class="form-group">
<label>Age</label>
<input type="text" formControlName="age" class="form-control" />
</div>
<div class="form-group">
<label>License Number</label>
<input type="text" formControlName="licenseNumber" class="form- control" />
</div>
</form>
@elementClass
Setting css class based upon some condition into a formControl. In this case the invalid class is applied when the state is touched or dirty and has errors
Stackblitz Example : Open
1) user.model.ts:
import { prop,elementClass,alpha } from "@rxweb/reactive-form-validators"
import { AbstractControl } from "@angular/forms"
export class User {
@elementClass({
conditionalExpression: function (control:AbstractControl) {
return (control.touched || control.dirty) && control.errors ? 'has- error' : '';
}})
@alpha()
userName: string;
}
2) user.component.ts:
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-add',
templateUrl: './user-add.component.html'
})
export class UserAddComponent implements OnInit {
userFormGroup: FormGroup;
constructor(private formBuilder: RxFormBuilder) { }
ngOnInit() {
let user = new User();
this.userFormGroup = this.formBuilder.formGroup(user);
}
}
3) user.component.html:
<form *ngIf="userFormGroup" [formGroup]="userFormGroup">
<div class="form-group">
<label>User Name</label>
<input type="text" formControlName="userName" class="form-control" />
</div>
</form>
@error
This decorator is used to display error based upon some condition. In this case the error messages are displayed when the submit button is clicked
Stackblitz Example : Open
1) form.model.ts:
import { required,error,prop } from "@rxweb/reactive-form-validators"
import {AbstractControl } from "@angular/forms"
export class FormField{
@prop()
action:string;
@error({conditionalExpression:function(control:AbstractControl){ return this.action === "submit"}})
@required()
firstName:string;
@error({conditionalExpression:function(control:AbstractControl){ return this.action == "submit"}})
@required()
userName:string;
}
2) user.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormGroup,Validators } from "@angular/forms"
import { RxFormGroup,FormGroupExtension,RxFormBuilder,FormBuilderConfiguration,RxwebValidators } from '@rxweb/reactive-form-validators';
import { FormField } from './form.model';
@Component({
selector: 'app-user-add',
templateUrl: './user-add.component.html'
})
export class UserAddComponent implements OnInit {
errorObject = {}
userInfoFormGroup: FormGroup
constructor(
private formBuilder: RxFormBuilder
) { }
ngOnInit() {
var formField = new FormField();
this.userInfoFormGroup =<RxFormGroup>this.formBuilder.formGroup(formField);
}
submit(){
if(this.userInfoFormGroup.invalid)
this.userInfoFormGroup.controls.action.setValue("submit");
}
}
3) user.component.html:
<form [formGroup]="userInfoFormGroup">
<div class="form-group">
<label>First Name</label>
<input type="text" formControlName="firstName" class="form-control" />
<small class="form-text text-danger" >{{userInfoFormGroup.controls.firstName["errorMessage"]}}</small>
</div>
<div class="form-group">
<label>User Name</label>
<input type="text" formControlName="userName" class="form-control" />
<small class="form-text text-danger" >{{userInfoFormGroup.controls.userName["errorMessage"]}}</small>
</div>
<button (click)="submit()" class="btn btn-primary">Submit</button>
</form>
Conclusion
This article show some of the best and most used cases which is fulfiled in the most intuitive and elegant way using model based approach, To know more about other useful decorators refer documentation section