Angular Forms - Form Types

Template-driven Forms

Template-driven forms

  • Simple, basic forms
  • Simple validations like:
    • Required
    • Min-length
    • Max-length
    • Pattern
  • Code is written mainly in the HTML-file

Declarations & Imports

//... imports
@NgModule({
  declarations: [
    AppComponent,
    YourFormComponent // <-- Your form component
  ],
  imports: [
    BrowserModule,
    FormsModule // <-- For template-driven forms
  ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }
Directives:
  • ngModel
  • NgForm

Injection

  • Importing FormsModule makes NgForm available to our view
  • NgForm will automatically be applied to the form-tag by definition:
    form:not([ngNoForm]):not([formGroup]),ngForm,[ngForm]
  • NgForm will automatically provide an (ngSubmit) output function

Meaning

<form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
      <label for="name">First name</label>
      <input id="name" name="name" ngModel>
</form>
  • ngForm is the FormGroup of NgForm
    • It is assigned to the local variable f
  • The attribute ngModel creates a new FormControl
    • Requires attribute name on element to create it
    • is automatically added to its parent FormGroup

Meaning

<form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
      <label for="name">First name</label>
      <input id="name" name="name" ngModel>
</form>
  • ngModel can be created as a
    • one-way data binding: ngModel (without value)
    • two-way data binding: [(ngModel)]="model.name"
  • ngModelGroup would let us make sub groups
  • ngModelArray is in development

Reactive Forms

Reactive forms

  • Complex forms
  • Complex validations like:
    • Validations going beyond RegExp
    • Validations being dependent on other fields
  • Dynamic visible fields, e.g. checkbox has to be shown if some specific select option has been selected
  • Better integrable with multi language / i18n support
  • The magic happens in the TS-File -> Easier to test

Declarations & Imports

//... imports
@NgModule({
  declarations: [
    AppComponent,
    YourFormComponent // <-- Your form component
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule // <-- For reactive forms
  ],
  providers: [],
  bootstrap: [ AppComponent ]
})
export class AppModule { }
Directives:
  • formControl
  • ngFormGroup

Injection

  • Importing ReactiveFormsModule provides us a FormBuilder
  • NgForm will NOT be added, as it doesn't match the selector. However, you can still use (ngSubmit) and [(ngModel)]
  • Add the attribute [formGroup] to the form-tag to use it as a reactive form
  • Add the attribute formControlName (or formControl) to each input field to bind it with your FormControl
  • use formGroupName on non-input elements to cope with nested FormGroups

Implications

  • We have to create all our FormControls, FormGroups and possible FormArrays in the TS-file
  • We can use FormBuilder to create those more easily

Meaning

<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)">
      <label for="firstName">First name</label>
      <input id="firstName" formControlName="firstName">
</form>
  • form is the FormGroup variable of our TS-file
  • NgForm is not used, as the selector does not match. Thus the attributes name and ngModel are no longer required.
  • formControlName="firstName" defines firstName as the key of the FormControl which we have to create in our TS-file.
  • There is also a formGroupName and formArrayName for nested objects and lists.