DEV Community

Cover image for Simplified Angular Reactive Forms
Ushmi Dave
Ushmi Dave

Posted on

Simplified Angular Reactive Forms

As we all know, Front end applications acquire lot of forms including basic and complex forms which we construct for various purpose like registering user's information, editing it, logging feedback and a lot more

While working with angular forms we first need to decide the type of form we want to make and the most preferred among them are Reactive forms because reactive forms allows multiple control to group, validate them and also provides advance form facilities like nested form groups and form arrays

Now, Imagine if you have a reactive form which needs all the above requirements with necessary validations just as the form shown below:

Reactive-form

The Component

Looking at the reactive features and validations used, it looks like the component must be having a lengthy code with lots of custom functions having custom business logic for performing the validations for array validation, comparing fields. The answer is No!!!

Have a look at the component code

   export class UserAddComponent implements OnInit {
    userFormGroup: FormGroup

    constructor(
        private formBuilder: RxFormBuilder
    ) { }

    ngOnInit() {
        let user = new User();
        user.hobbies = new Array<Hobby>();
        user.address = new Address();
        let hobby = new Hobby();
        user.hobbies.push(hobby);
        this.userFormGroup = this.formBuilder.formGroup(user);
        }

    addAddress(){
      let addresses = this.userFormGroup.controls.hobbies as FormArray;
      addresses.push(this.formBuilder.formGroup(Hobby));
    }
}
Enter fullscreen mode Exit fullscreen mode

This is achieved with the help of using formGroup method of RxFormBuilder which groups the controls which are the properties of the model class.

RxFormBuilder is a part of @rxweb/reactive-form-validators.
RxWeb contains various methods for form reset, globally bind error message strategy, patch value, strongly typed reactive forms and a wide range of validations including compose validation, compare validation, unique validation, async validation and tempate driven validation and a lot more. For more information on how to achieve it have a look at this article on New way to validate angular reactive forms

The Model

The source code file where the properties and validations are managed is the model class. In this approach the controls are not managed at the component level but managed at the model level because this file is considered base root for managing the properties which strengthens you to take advantage of the object oriented concepts into typescript, Other benefit of model class is that its properties can be used as a control in other components as well which means code can be reused and the complexity level of your component decreases.

Dependency-Diagram

The model class file is as below:

import { email,unique,alpha,compare,prop, propArray, propObject } from "@rxweb/reactive-form-validators"

export class Hobby {
  @unique()
  hobbyName: string;
}

export class  Address{
  @prop()
  city: string;

  @prop()
  country: string;
}

export class User {

  @alpha()
  firstName: string;

  @alpha()
  lastName: string;

  @email()
  email: string;

  @prop()
  password: string;

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

  @propObject(Address)
  address: Address;

  @propArray(Hobby)
  hobbies: Hobby[];
}

Enter fullscreen mode Exit fullscreen mode

Html

The controls of the formGroup are finally bind as an input for rendering them into the Html DOM which are further used for getting input from the user. In case of validations to display the validation messages we need to write *ngIf conditions for touched, invalid, dirty etc... But here i have used just one condition which will display my errorMessage whenever the state of form is invalid. Here is my complete HTML code.

<form *ngIf="userFormGroup" [formGroup]="userFormGroup">
<div class="form-group">
   <label>FirstName</label>
   <input type="text" formControlName="firstName" class="form-control" />
   <small class="form-text text-danger" *ngIf="userFormGroup.controls.firstName.errors">{{userFormGroup.controls.firstName.errors.alpha.message}}<br/></small>  
</div>
<div class="form-group">
   <label>LastName</label>
   <input type="text" formControlName="lastName" class="form-control" />
   <small class="form-text text-danger" *ngIf="userFormGroup.controls.lastName.errors">{{userFormGroup.controls.lastName.errors.alpha.message}}<br/></small>
</div>
<div class="form-group">
   <label>Email</label>
   <input type="text" formControlName="email" class="form-control" />
   <small class="form-text text-danger" *ngIf="userFormGroup.controls.email.errors">{{userFormGroup.controls.email.errors.email.message}}<br/></small>  
</div>
<div class="form-group">
   <label>Password</label>
   <input type="password" formControlName="password" class="form-control" />
</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.message}}<br/></small>    
</div>
<div class="card">
   <div class="card-header"><label class="card-title">Address</label>
   </div>
   <div class="card-body">
      <div  [formGroup]="userFormGroup.controls.address">
         <div class="form-group">
            <label>City</label>
            <input type="text" formControlName="city" class="form-control" />
         </div>
         <div class="form-group">
            <label>Country</label>
            <input type="text" formControlName="country" class="form-control" />
         </div>
      </div>
   </div>
</div>
<div class="card">
   <div class="form-group">
      <div class="card-header">
         <label class="card-title">Hobbies</label>
         <button (click)="addAddress()" class="pull-right"><i class="fa fa-plus"></i></button>
      </div>
      <div class="card-body"  [formGroup]="hobby" *ngFor="let hobby of userFormGroup.controls.hobbies.controls; let i = index">
      <label>{{i+1}} Hobby</label>
      <input  type="text" formControlName="hobbyName" class="form-control" />
      <small class="form-text text-danger" *ngIf="hobby.controls.hobbyName.errors">{{hobby.controls.hobbyName.errors.unique.message}}<br/></small>
   </div>
</div>
</div>
<button (click)="onSubmit()" [disabled]="!userFormGroup.valid" class="btn btn-primary">Submit</button>
<br/>
{{userFormGroup.value | json}}
</form>
Enter fullscreen mode Exit fullscreen mode

Here is the complete example on stackblitz. Feel free to share your feedback, you can also give your suggestion on gitter channel.

Top comments (1)

Collapse
 
jwp profile image
John Peters

Nice..Thanks!