Sunday, January 9, 2022

Angular Reactive Form Example

In this post we’ll see how to build a reactive form in Angular which is also known as Model-driven form.

Importing ReactiveFormsModule

You need to import ReactiveFormsModule into the AppModule (app.module.ts) for Angular Reactive form to work. Add ReactiveFormsModule in the imports section of the AppModule.

imports: [
  BrowserModule,
  ReactiveFormsModule
],

Reactive Form example Application in Angular

In the example we’ll create a form with two input fields for name and email, a date picker for picking date and a drop down to select one of the option. Once finsihed our form should look something like this-

Angular Reactive Form Example

Data Model

Member class defines the data model reflected in the form.

member.model.ts

export class Member {
  name: string;
  mail: string;
  membershipDate: Date;
  membershipType: string;
  constructor(name: string, mail: string, membershipDate: Date, membershipType: string) {
    this.name = name;
    this.mail = mail;
    this.membershipDate  = membershipDate;
    this.membershipType = membershipType;
  }
}

Component class (app.component.ts)

In ReactiveForm you create the form controls in the Component class which you will sync up with the corresponding template.

To create Angular Reactive form you will mainly use FormControl, FormGroup and FormArray classes. A FormControl represents an individual form control where as FormGroup represents a collection of form controls as a group. So, it is obvious that in your code you will create a FormGroup object and with in that you will add form controls corresponding to fields in the form.

import { DatePipe } from '@angular/common';
import { Component, OnInit} from '@angular/core';
import { FormControl, FormGroup} from '@angular/forms';
import { Member } from './member.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html', 
  providers: [DatePipe]
})
export class AppComponent implements OnInit {
  membershiptypes = ['Silver', 'Gold', 'Platinum'];
  currentDate = new Date();
  member = new Member('', '', new Date(), '');
  submitted = false;
  membershipForm : FormGroup;
  constructor(private datePipe: DatePipe){ }
  ngOnInit() {
    this.membershipForm = new FormGroup({
      memberName: new FormControl(null),
      email: new FormControl(null),
      mdate: new FormControl(this.datePipe.transform(this.currentDate, 'yyyy-MM-dd')),
      membershipType: new FormControl('Silver')
    });
  }
  onSubmit(){
    this.submitted = true;
    this.member.name = this.membershipForm.value.memberName;
    this.member.mail = this.membershipForm.value.email;
    this.member.membershipDate = this.membershipForm.value.mdate;
    this.member.membershipType = this.membershipForm.value.membershipType; 
  }
}

Important points to note here are-

1. You need to import FormControl and FormGroup classes.

2. A reference to FormGroup is created named membershipForm.

3. Using that reference a new FormGroup object is created and an array of form controls are added to that FormGroup object.

4. A FromControl takes three arguments state, Validator and AsyncValidator. In this example we are not going into validation so we’ll pass just one argument. For name and email initial value is passed as null. For date current date is passed as default and for Membership type ‘Silver’ is passed as default. For validation in reactive form check this post- Angular Reactive Form Validation Example

5. onSubmit() method is called when the form is submitted and the values entered in the form are used to create an object of Member class.

Template (app.component.html)

<div class="container">
  <div class="row">
    <div class="col-xs-12 col-sm-10 col-md-8">
      <h1>Membership Form</h1>
      <form [formGroup]="membershipForm" (ngSubmit)="onSubmit()">
        <div class="form-group">
          <label for="name">Name</label>
          <input type="text" class="form-control" id="name"
                 formControlName="memberName">                        
        </div>
        <div class="form-group">
          <label for="email">email</label>
          <input type="email" class="form-control" id="email"
          formControlName="email">                        
        </div>
        <div class="form-group">
          <label for="mdate">Membership Date</label>
          <input type="date" class="form-control" id="mdate"
          formControlName="mdate">                        
        </div>
        <div class="form-group">
          <label for="type">Membership Type</label>
          <select class="form-control" id="type"                    
          formControlName="membershipType">
            <option *ngFor="let mtype of membershiptypes" [value]="mtype">{{mtype}}</option>
          </select>
        </div>
        <button type="submit" class="btn btn-success">Submit</button>
      </form> 
    </div>
  </div>
  <hr>
  <div *ngIf="submitted">
    <div class="row">
      <div class="col-xs-12 col-sm-10 col-md-8">
        <p>Name: {{member.name}}</p>
        <p>email: {{member.mail}}</p>
        <p>Membership Date: {{member.membershipDate | date:'dd/MM/yyyy'}}</p>
        <p>Membership Type: {{member.membershipType}}</p>
      </div>
    </div>
  </div>  
</div>

Important points to note here are-

1. You need to tell the template, from where it has to get all the FormControls for the form, that is done by binding the FormGroup reference.

 <form [formGroup]="membershipForm" (ngSubmit)="onSubmit()">

2. For syncing up the form controls you will have to bind each form field with the form control created in the component. That is done by assigning formControlName to the name given in the component.

<input type="text" class="form-control" id="name"
                 formControlName="memberName">  

3. For Membership Type dropdown, options are added using ngFor which iterates over an array called membershiptyes defined in the Component class.

4. Submit button is of type submit so it will trigger a submit event for that event binding is done at the form level.

 <form [formGroup]="membershipForm" (ngSubmit)="onSubmit()">

5. There is another row which just displays the entered values after the form is submitted. There is a 'submitted' field which is assigned value true in the onSubmit() method.

Reactive form creation

That's all for this topic Angular Reactive Form Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Angular Tutorial Page


Related Topics

  1. Angular Reactive Form Validation Example
  2. Angular Template-Driven Form Validation Example
  3. FormBuilder in Angular Example
  4. Custom Async Validator in Angular Reactive Form
  5. Radio Button in Angular Form Example

You may also like-

  1. Angular ngIf Directive With Examples
  2. Angular Cross Component Communication Using Subject Observable
  3. Setting and Fetching Route Parameters in Angular
  4. Angular Custom Two-Way Data Binding
  5. Java CyclicBarrier With Examples
  6. this Keyword in Java With Examples
  7. Java Multithreading Tutorial
  8. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example

3 comments:

  1. Not Working In angular 13.

    ReplyDelete
  2. ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(BaseModule)[DatePipe -> DatePipe -> DatePipe -> DatePipe]:
    NullInjectorError: No provider for DatePipe!
    NullInjectorError: R3InjectorError(BaseModule)[DatePipe -> DatePipe -> DatePipe -> DatePipe]:
    NullInjectorError: No provider for DatePipe!
    at NullInjector.get (core.mjs:11145:1)
    at R3Injector.get (core.mjs:11312:1)
    at R3Injector.get (core.mjs:11312:1)
    at R3Injector.get (core.mjs:11312:1)
    at NgModuleRef.get (core.mjs:21872:1)
    at R3Injector.get (core.mjs:11312:1)
    at NgModuleRef.get (core.mjs:21872:1)
    at Object.get (core.mjs:21549:1)
    at lookupTokenUsingModuleInjector (core.mjs:3358:1)
    at getOrCreateInjectable (core.mjs:3470:1)
    at resolvePromise (zone.js:1211:1)
    at resolvePromise (zone.js:1165:1)
    at zone.js:1278:1
    at _ZoneDelegate.invokeTask (zone.js:406:1)
    at Object.onInvokeTask (core.mjs:25579:1)
    at _ZoneDelegate.invokeTask (zone.js:405:1)
    at Zone.runTask (zone.js:178:1)
    at drainMicroTaskQueue (zone.js:585:1)
    at ZoneTask.invokeTask [as invoke] (zone.js:491:1)
    at invokeTask (zone.js:1648:1)
    defaultErrorLogger @ core.mjs:6485
    handleError @ core.mjs:6532
    next @ core.mjs:26158
    next @ Subscriber.js:91
    _next @ Subscriber.js:60
    next @ Subscriber.js:31
    (anonymous) @ Subject.js:34
    errorContext @ errorContext.js:19
    next @ Subject.js:27
    emit @ core.mjs:22467
    (anonymous) @ core.mjs:25618
    invoke @ zone.js:372
    run @ zone.js:134
    runOutsideAngular @ core.mjs:25491
    onHandleError @ core.mjs:25618
    handleError @ zone.js:376
    runGuarded @ zone.js:147
    api.microtaskDrainDone @ zone.js:1072
    drainMicroTaskQueue @ zone.js:592
    invokeTask @ zone.js:491
    invokeTask @ zone.js:1648
    globalCallback @ zone.js:1679
    globalZoneAwareCallback @ zone.js:1712

    ReplyDelete
    Replies
    1. If it is a DatePipe problem then ensure that it is added in providers section of Component
      providers: [DatePipe]
      Refer AppComponent code. You can also add it in the providers section of app.module.ts

      Delete