DEV Community

Ricardo Torres
Ricardo Torres

Posted on • Originally published at ricardo-torres.me on

Angular Forms

If you started learning Angular from version 1 (AngularJs), maybe you will be more familiarized with configuring a clean Html to handle states and validations in the form. This approach is known as Template-Driven Forms.

In contrast Angular count with Model-Dirven Forms or Reactive Forms which delegates most of the responsability to apply validations and keep states (valid, invalid, touched and dirty) in the form over an object called FormControl located in the TypeScript and not in the HTML like the Template-Driven Forms.

Template Driven Forms

| Pros | Cons |
| -Very easy to write | Require more lines of HTML code and it can turn it difficult to mantain. |
| -Easy to read and understand | It can not be tested, there is no way to apply unit test to their validators. |

Reactive Forms

This powerful module provides a way to define a form as a FormGroup in the TypeScript class to handle states and validations rules that will be associated to each input in the form throught a formControlName.

Personally, I think that both are good ways to create Forms in Angular, but your decision over one or another approach is up your needs, the complexity of the forms, if you must create smalls forms with a low complexity you can use Template-Driven Forms, but if you need to create complex forms with Unit test, Reactive Forms will be a smart decision.

Let's create our first Reactive Form.

Open your console and type:

ng new reactive-forms
Enter fullscreen mode Exit fullscreen mode
? Would you like to add Angular routing? (y/N) y
Enter fullscreen mode Exit fullscreen mode


cd reactive-forms
Enter fullscreen mode Exit fullscreen mode
cd .\src\app
Enter fullscreen mode Exit fullscreen mode

Import the module ReactiveFormsModule in the app.module.ts

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HeaderComponent } from './layout/header/header.component';
import { FooterComponent } from './layout/footer/footer.component';
import { HttpClientModule } from '@angular/common/http';
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  declarations: [AppComponent, HeaderComponent, FooterComponent],
  imports: [BrowserModule, AppRoutingModule, HttpClientModule, ReactiveFormsModule],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}

Enter fullscreen mode Exit fullscreen mode

Create a folder inside app named components and create a component called create-fruits

ng g c create-fruits
Enter fullscreen mode Exit fullscreen mode

Define the structure of the Form in the class CreateFruitsComponent

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Record } from 'src/app/model/record';

@Component({
  selector: 'app-create-fruits',
  templateUrl: './create-fruits.component.html',
  styleUrls: ['./create-fruits.component.scss'],
})
export class CreateFruitsComponent implements OnInit {
  title!: string;
  form!: FormGroup;
  fruit!: Record;

  constructor() {}

  ngOnInit(): void {
    this.form = new FormGroup({
      name: new FormControl('', [Validators.required]),
      description: new FormControl('', [Validators.required]),
      image: new FormControl('', [Validators.required]),
      price: new FormControl(0, [Validators.required]),
    });
  }

  onSubmit(): void {
    console.log(this.form);
  }
}
Enter fullscreen mode Exit fullscreen mode

As I mentioned before, defining the form in the TypeScript provides a good way to handle the states of our form and all the formControls inside it.

create-fruits.component.html

<section class="section">
  <div class="container">
    <h1>New Fruit</h1>
    <div class="form" [formGroup]="form" (ngSubmit)="onSubmit()">
      <div class="form-group">
        <label class="label">Name :</label>
        <input
          type="text"
          id="name"
          formControlName="name"
          placeholder="Name"
          class="input"
        />
        <p
          class="help is-danger walkP"
          *ngIf="
            (form.controls['name'].dirty || form.controls['name'].touched) &&
            form.controls['name'].errors &&
            form.controls['name'].errors['required']
          "
        >
          Name is required!
        </p>
      </div>

      <div class="form-group">
        <label class="label">Description :</label>
        <input
          type="text"
          id="description"
          formControlName="description"
          placeholder="Name"
          class="input"
        />
        <p
          class="help is-danger walkP"
          *ngIf="
            (form.controls['description'].dirty ||
              form.controls['name'].touched) &&
            form.controls['description'].errors &&
            form.controls['description'].errors['required']
          "
        >
          Description is required!
        </p>
      </div>
      <div class="form-group">
        <label class="label">Image :</label>
        <input
          type="text"
          id="image"
          formControlName="image"
          placeholder="Image"
          class="input"
        />
        <p
          class="help is-danger walkP"
          *ngIf="
            (form.controls['image'].dirty || form.controls['name'].touched) &&
            form.controls['image'].errors &&
            form.controls['image'].errors['required']
          "
        >
          Image is required!
        </p>
      </div>
      <div class="form-group">
        <label class="label">Price :</label>
        <input
          type="number"
          id="price"
          formControlName="price"
          placeholder="Price"
          class="input"
        />
        <p
          class="help is-danger walkP"
          *ngIf="
            (form.controls['price'].dirty || form.controls['name'].touched) &&
            form.controls['price'].errors &&
            form.controls['price'].errors['required']
          "
        >
          Image is required!
        </p>
      </div>
      <div class="field is-grouped">
        <div class="control">
          <button
            type="submit"
            class="button is-success"
            (click)="onSubmit()"
            [disabled]="!form.valid"
          >
            Save
          </button>
        </div>
        <div class="control">
          <button class="button is-warning">Cancel</button>
        </div>
      </div>
    </div>
  </div>
</section>

Enter fullscreen mode Exit fullscreen mode

Note that I am not using the classic tag form to encapsulate all my html elements, it is not necesary , because I am using a div with a [formGroup]="form" , additionally I am associating each input with its right formControl defined in the TypeScript.

I hope that this post help you in your learning of Angular.

Live Demo

Download Code

Top comments (0)