Exploring Angular Reactive Module

Exploring Angular Reactive Module

Introduction
———–

Forms are probably the most crucial aspect of a enterprise web application. Forms is the component where we get the majority of our rich data input from users. There are two different approaches to build forms in Angular. The first category are the template-driven forms. Using this method, you first create html-input-elements and then use directives like ngModel to bind their value to a component’s variable. The second category are Reactive Forms: this feature allow you to define the form via code instead of defining the form in your template. In addition with Reactive form you can manage the input flow and validation with a reactive programming approach using Rxjs. In this article i’ll introduce you Reactive Form with a simple example.

Create our first Reactive Form
———–
The example is a registration user form. In order to registrate a new user in the system, the user must complete the following input fields:

  • Username (* mandatory)
  • Password (* mandatory – must be at least 5 characters long)
  • Confirm Password (* mandatory – must be equal to previous input)
  • Email (* mandatory – must be a valid email address)

![enter image description here](https://italiancoders.it/wp-content/uploads/2019/04/example-form.png)

In order to use Reactive Forms in our app, we have to first import ReactiveFormsModule in **app.module.ts** from @angular/forms, and then add in the @NgModule imports.

```typescript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

The fundamental components of Reactive form features are **FormControl** and **FormGroup**. The **FormControl** is a class that powers an individual form control, tracks the value and validation status, offering a wide set of API. Below is a basic example of Form group that implement the form of our example.

```html

Angular Reactive Form

User Name is required
Username must be at least 4 characters
Email is required
Email must be a valid email address
Password is required
Password must be at least 6 characters
Confirm Password is required
Passwords must match
``` ```typescript @Component({ selector: 'app', templateUrl: 'app.component.html' }) export class AppComponent implements OnInit { registerForm: FormGroup; constructor(private formBuilder: FormBuilder) { } ngOnInit() { this.registerForm = this.formBuilder.group({ username: ['', [Validators.required, Validators.minLength(4)]], email: ['', [Validators.required, Validators.email]], password: ['', [Validators.required, Validators.minLength(6)]], confirmPassword: ['', Validators.required], }, { validator: MustMatch('password', 'confirmPassword') }); } get f() { return this.registerForm.controls; } onSubmit() { // stop here if form is invalid if (this.registerForm.invalid) { return; } console.log('send data', this.registerForm.value) } } ```

As you can see, for each form control you have to define the key that represent the control of the form. In this way you can bind the form group and each of its form controls defined in the typescript component with the form and its input component’s defined in the html.

Form Validation
———–
Most of the forms required input validation before to submit the data to the backend. Angular is really powerful in this respect: the framework offers a lot of predefined validation’s (Validators.required, Validators.email, etc) but you can define also your custom logic to validate the input. You can define one or more validation’s at the form group level or at form control level. Angular perform the control validation for each input change of that input control.
If you check the code of our example you can see that:

– i have configured the validations requested for each control ( for i.e i have configured the mandatory and min length constraint of the username input configuring the form control with the core validations: **Validators.required** and **Validators.minLength(4)**).
– if the last validation was failed, Angular set the field errors of that control with the validation failed in order to show the error in the html.

```html
        
User Name is required
Username must be at least 4 characters
```

As you can see above, i show under the input field an error message if the validation was failed checking the errors field of that control.
– i have defined also a validation at form group level. In particular i want to check that password and confirm password must contain the same text. To do that i have developed a custom validation: **MustMatch** that check if the two password are valid and that they are identical.

```typescript
import { FormGroup } from '@angular/forms';

// custom validator to check that two fields match
export function MustMatch(controlName: string, matchingControlName: string) {
    return (formGroup: FormGroup) => {
        const control = formGroup.controls[controlName];
        const matchingControl = formGroup.controls[matchingControlName];

        if (matchingControl.errors && !matchingControl.errors.mustMatch) {
            // return if another validator has already found an error on the matchingControl
            return;
        }

        // set error on matchingControl if validation fails
        if (control.value !== matchingControl.value) {
            matchingControl.setErrors({ mustMatch: true });
        } else {
            matchingControl.setErrors(null);
        }
    }
}

```

```typescript
... // other form control definition
{
            validator: MustMatch('password', 'confirmPassword')
        }

```

– If one or more validation’s are failed, Angular set the as true the **invalid** field of the form. In this way you can disable the submit button if the form is invalid.

Async Validation
———–
In many cases the data of a form must be validated by the backend: for example in a user registration form, the backend must validate the username in order to verify that the username entered has not already been used. In these cases it is necessary to develop an asynchronous validator, which invokes an api rest that which checks the existence of the username entered and in this case makes validation fail.

Suppose we have a service **userService** that offer the following method:

```typescript
.getUsersByUsername(username: string): Observable
```
that return the users that have a given username, we can develop an async validator in this way:
```typescript
export function existingUsername(userService: UserService): AsyncValidatorFn {
  return (control: AbstractControl): Promise | Observable => {
    return userService.getUsersByUsername(control.value).map(
      (user) => user != null && user.length > 0 ? {"userAlreadyExist": true} : null
    );
  };
} 
```

We can therefore add the new validation inside the form control definition and display in the html the error

the username choosen is already used in the system

when **f.username.errors.userAlreadyExist** is true

Listen input change using rxjs stream
———–
Reactive forms provide a model-driven approach to handling form inputs whose values change over time. Indeed reactive form instances like **FormGroup** and **FormControl** have:

– **_valueChanges_** method that returns an observable that emits an event every time when the value of control changes either using UI or programmatically.
– **statusChanges** method that returns an observable that emits an event every time when the validation status of the control is re-calculated.
You can therefore subscribe to **valueChanges** or **statusChanges** to update instance variables or perform operations.
For example i can listen the username input changes in this way

```typescript
this.registerForm.get('username').valueChanges.subscribe((u) => console.log(u));
```

Conclusion
———–
In this article has been introduced reactive form feature: a fantastic approach to managing forms that is more scalable, testable, reusable, and robust compared to template driven form. The source code of the example shown in this article can be found at this link: https://stackblitz.com/edit/angular-7-reactive-form-validation-itc

Leave a Reply

Your email address will not be published.