DEV Community

Cover image for Simplified Angular Reactive Forms
Ushmi Dave
Ushmi Dave

Posted on

5 2

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.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (1)

Collapse
 
jwp profile image
JWP

Nice..Thanks!

The best way to debug slow web pages cover image

The best way to debug slow web pages

Tools like Page Speed Insights and Google Lighthouse are great for providing advice for front end performance issues. But what these tools can’t do, is evaluate performance across your entire stack of distributed services and applications.

Watch video

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay