Angular 4 Reactive forms - MaorZ/MaorZTech GitHub Wiki

Angular 4 - Reactive forms - The journey to totally dynamic form generator - Part 1

Motivation

In most of our applications (especially in the REST ones), we will need to use forms as our main tool (to add/update our data). In most the cases we find ourselves writing a standard form html template with the field names and the validation messages and ng-ifs.

My motivation is to make a single component that gets an JS Object (hard-coded or from a DB) and will generate all the template for you, including:

  • field name and template
  • field label
  • field value
  • field validation types (and their messages)
  • vireos types of fields (known ones like textbox and checkbox and a custom ones that are custom created)
  • and much more complicated things that we can do in a non simple form

How to get there

In order to get there we need to check what tools the Angular world has to offer:

Template-driven forms

the good old Template driven way to create forms (more like the AngularJs 1.x way) by using the ngModel directive for our 2 way binding and the ngForm directive to hold all the state of the form (for validations and state managing), this means less code in the component class.

This case is good for the simplest most shortest forms to fill.

The problems with this way is that all of the template is hardcoded (also the field names) and the templates will be pretty long and hard to change when time comes. Also more complex things like a live changing form by its state will be hard to write.

Also the template-driven forms are asynchronous which may complicate development in more advanced scenarios.

I'm sure that you are familiar with this type of technology (as it very similar to AngularJs 1.x), but if not you can read all about it in the official Angular site: Angular -> Guide -> Forms.

Reactive forms

In this technology we will create our own form object tree with the following classes:

  • AbstractControl - This is the parent class for all the Form Control types. It hold all the base properties for every type of the form group.
  • FormControl - Is a simple reference for a single field. Holds the value and state of the field.
  • FormGroup - Holds a group of AbstractControl members and a summery the state of all them.
  • FormArray - Holds an array of AbstractControl members (indexed from 0 to N) and a summery the state of all them.

This technology will be our base for starting our Totally Dynamic Form Generator component.

Let's start coding!

Part 1 will go through the basics of the Reactive Forms technology.

Lets create our first reactive form: A simple form that will return a User type object defined as:

class User {
  full_name: String;
  age: Number;
}

First lets create our Module file:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';  // <-- Here we import the Reactive forms module
                                                       //     It exports the original FormsModule

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

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

Now let's create the AppComponent:

app.component.ts

import { Component } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';

@Component({
  select: 'app',
  templateUrl: './app.component.html'
})
export class AppComponent {
  userForm: FormGroup; // <-- This is our main Form Tree object

  constructor() {
    userForm = new FormGroup ({
      full_name: new FormControl(),
      age: new FormControl()
    });
  }

  ...
}

app.component.html

<form [formGroup]="userForm" novalidate>
  <div class="form-group">
    <label class="center-block">Full Name:
      <input class="form-control" formControlName="name">
    </label>
  </div>
  <div class="form-group">
    <label class="center-block">Age:
      <input class="form-control" formControlName="age">
    </label>
  </div>
</form>
⚠️ **GitHub.com Fallback** ⚠️