Reactive Forms : Angular
Tags: angular, webdev, javascript, typescript
Published: 2021-07-14 09:12:56

## Objective

Create a Form with the following Controls and Validators
          1) Project Name (should not be empty)
          2) Mail (should not be a empty and a valid email)
          3) Project Status Dropdown, with three values: 'Stable', 'Critical', 'Finished'
          4) Submit Button
          Add your own Validator which doesn't allow "Test" as a Project Name
          Also implement that Validator as an async Validator (replace the other one)
          Upon submitting the form, simply print the value to the console

## Code

- app.module.ts - ReactiveFormsModule is important here

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


import { AppComponent } from './app.component';

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

- app.component.ts
```typescript
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ProjectNameValidator } from './projectname-validator';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
  projectStatus = ['Stable', 'Critical', 'Finished']

  contactForm = new FormGroup({
    projectName: new FormControl('', [Validators.required, ProjectNameValidator.invalidProjectName], ProjectNameValidator.asyncInvalidProjectName),
    emailId: new FormControl('', [Validators.required, Validators.email]),
    projectDetails: new FormControl('Critical')
  });

  onSubmit() {
    console.log(this.contactForm.value);
  }

  get projectName() {
    return this.contactForm.get('projectName');
  }

  get emailId() {
    return this.contactForm.get('emailId');
  }

  get projectDetails() {
    return this.contactForm.get('projectDetails');
  }

  ngOnInit(){

  }
}
```

- app.component.html
```html
<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
      <!--
          Create a Form with the following Controls and Validators
          1) Project Name (should not be empty)
          2) Mail (should not be a empty and a valid email)
          3) Project Status Dropdown, with three values: 'Stable', 'Critical', 'Finished'
          4) Submit Button

          Add your own Validator which doesn't allow "Test" as a Project Name

          Also implement that Validator as an async Validator (replace the other one)

          Upon submitting the form, simply print the value to the console
      -->
      <form [formGroup]="contactForm" (ngSubmit)="onSubmit()" novalidate>
        <div class="form-group">
          <label for="project">ProjectName</label>
          <input type="text" id="projectName" name="projectName" class="form-control" formControlName="projectName">
          <div class="alert alert-danger" role="alert" *ngIf="!projectName.valid && (projectName.dirty || projectName.touched)">
            <div class="alert alert-danger" *ngIf="projectName.errors.required">
              Project Name is required, Please enter a valid one. Thank you
            </div>
            <div class="alert alert-danger" *ngIf="projectName.errors.invalidProjectName">
              Project Name is should not be Test
            </div>
            <div class="alert alert-danger" *ngIf="projectName.errors.asyncInvalidProjectName">
              Project Name is should not be test
            </div>
          </div>
        </div>
        <div class="form-group">
          <label for="project">Email</label>
          <input type="text" id="emailId" name="emailId" class="form-control" formControlName="emailId">
          <div class="alert alert-danger" role="alert" *ngIf="!emailId.valid && (emailId.dirty || emailId.touched)">
            <div class="alert alert-danger" *ngIf="emailId.errors.required || emailId.errors.email">
              Email id is required, please enter a valid one
            </div>
            </div>
          </div>
        <div class="form-group">
          <label for="project">Project Status</label>
          <select name="projectStatus" id="projectStatus" class="form-control" formControlName="projectDetails">
            <option *ngFor="let status of projectStatus" [value]="status"> {{ status }}</option>
          </select>
        </div>
        <button class="btn btn-primary" type="submit" [disabled]="!contactForm.valid">Submit</button>
      </form>
      <br>
      <div class="container-fluid">
        <pre>{{ contactForm.value | json}}</pre>
      </div>
    </div>
  </div>
</div>
```

- projectname-validator.ts

```typescript
import { FormControl } from "@angular/forms";
import { Observable } from "rxjs";

export class ProjectNameValidator {
    static invalidProjectName(control: FormControl): {[s:string]: boolean} {
        if (control.value === 'Test') {
            return {'invalidProjectName': true};
        }
        return null;
    }

    static asyncInvalidProjectName(control: FormControl): Promise<any> | Observable<any> {
        const promise = new Promise((resolve, reject) => {
            setTimeout(() => {
                if (control.value === 'test') {
                    resolve({'asyncInvalidProjectName': true});
                }
                else {
                    resolve(null);
                }
            }, 2000)
        })
        return promise;
    }
}
```

## Output

{% stackblitz reactive-angularform file=src/app/app.component.html %}

{% github Rohithv07/Extra-Material-For-Angular %}