A new way to validate Angular Forms
If you're working on more data-oriented advanced reactive forms, you'll find that not just inputs, but some of the validators and general stuff aren't readily available in the Angular framework. Then design a custom validation and subscribe to FormControl value changes to meet the functional needs of your application. Most of the time this leads to extra noise in your code and you end up doing the same thing over and over.
Lists some of the current challenges in reactive form validation.
? So there is no simple model object that can define properties based on their respective data types and map directly to reactive forms.
? It is not possible to directly map model object values to reactive forms using validation while creating a FormGroup.
? Manually configure validators for each corresponding property (FormControl).
? If you have a specific need to perform different operations based on each FormControl value change, you should subscribe to corresponding FormControl value changes and perform further activities. This is a bit difficult to handle with large forms.
?? Too much code to manage cross-field and conditional validation when a given FormControl has multiple validators.
Use @rxweb/reactive-form-validators for Angular reactive forms to tackle new approaches and overcome current challenges.
Why @rxweb/reactive-form-validators?
Speaking of typescript, the typescript programming language relies heavily on object-oriented programming techniques that provide more opportunities for writing clean code. This is the main reason why we designed this framework to provide reactive forms based on model objects. This will increase the complexity of your application form, and as your application grows at that point, you will have more flexibility, so don't get bogged down in the chore of compiling subscriptions for validators and other values.
Let's create a model object-based reactive form with decorator-based validation. What is decorator-based validation?
Suppose you only want a few validations on the userName field, such as alpha, minLength, and required. These validations can be set in the form of validation decorators on the userName property of the user model. @rxweb/reactive-form-validators add the configured validation decorators when creating the FormControl for the userName property. Here is a code example:
Functional RequirementHere is the registration form mockup, functional needs and validation rules.
export class User
??? @alpha()
??? @minLength({ value: 5 })
??? @required()
??? userName: string;
}{
User registration form model.
1. All fields marked in red are required.
2. field is valid only if the password and confirmation field values are the same.
3. The fullName property is read-only and represents the combined value of firstName and lastName. When the user enters a value in the appropriate FormControl, the updated value of fullName is immediately reflected in the UI.
The package?installation command?is:
npm install @rxweb/reactive-form-validators
Once the package is installed, We register the?'RxReactiveFormsModule'?in?his?root?module, allowing him?to?use?the services of this framework.
领英推荐
The next?code?sample is
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 { };
Once the?RxReactiveFormsModule?is registered, Now we creates a User model with?the appropriate?properties shown in the mockup and applies validation decorators?to?the?required?properties?in?the registration?form.
export class User
??? @required()
??? firstName: string;
?
??? @required()
??? lastName: string;
?
??? @required()
??? userName: string;
?
??? @required()
??? password: string;
}{
Following?the?code above,?We applied the?necessary?validation?decorators to the appropriate fields?but missed the second and?third scenarios. In
let's see?how the second and?third?scenarios come true.
The?second scenario is?that he?compares the?values of two controls to meet a requirement. We use a comparison decorator that compares?FormControl?values between fields.
ConfirmPassword's?only property and applied validation?decorator:
@compare({fieldName:'password'}
confirmPassword:string;)
Here,?to achieve the third scenario, We?do?not subscribe?to his?ValueChanges property, and?when?the?value changes to firstName or lastName He sets a?value in the fullName?field. We make some modifications to?the already defined first name and last name?properties. For us, for firstName and lastName he?uses getter/setter typescript?functions. Here?are the changes:
private _firstName: string = ''
??? private _lastName: string = '';
?
??? fullName: string;
?
??? @required()
??? set firstName(value: string) {
??????? this._firstName = value;
??????? this.setFullName();
??? }
?
??? get firstName(): string {
??????? return this._firstName;
??? }
?
??? @required()
??? set lastName(value: string) {
??????? this._lastName = value;
??????? this.setFullName();
??? }
?
??? get lastName(): string{
?????? return this._lastName;
??? }
?
??? setFullName() {
??????? this.fullName = `${this.firstName} ${this.lastName}`;
??? };
We applied?his getters/setters to?the firstName and lastName?properties?and created a method?for?setFullName?to update?the?full name value.?Now?the?question arises:
Why?did?We?use the?getter/setter?properties? Called with?a value.?Within?the setter function, We set the value?of his?private property?to?the?corresponding?public?property. This?makes your?application?more flexible?as the same model?is used?in multiple components. We?don't?need to write the same code in multiple components?or?subscribe to ValueChanges. See the?illustration below
The setter function will call when the firstName FormControl value change.
Now let’s see, the complete User model
import { required,compare } from "@rxweb/reactive-form-validators"
export class User {
??? private _firstName: string = '';
??? private _lastName: string = '';
??? fullName: string;
??? @required()
??? set firstName(value: string) {
??????? this._firstName = value;
??????? this.setFullName();
??? }
??? get firstName(): string {
??????? return this._firstName;
??? }
??? @required()
??? set lastName(value: string) {
??????? this._lastName = value;
??????? this.setFullName();
??? };
Now, We create a FormGroup from the User model object in the component. We use the ‘form group’ method of RxFormBuilder for creating a FormGroup.
Here is the code :
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
??? user:User;
??? constructor(
??????? private formBuilder: RxFormBuilder
??? ) { }
?
??? ngOnInit() {
??????? this.user = new User();
??????? this.userFormGroup = this.formBuilder.formGroup(this.user);
??? }
};
Now, We write the HTML as per angular reactive form standards. But the fullName property is not a FormControl. We used the user object for showing the full name value. See the below code:
<div class="form-group"
??? <label>Full Name : {{user.fullName}}</label>
? </div>>