Skip to content

Instantly share code, notes, and snippets.

@killerchip
Created January 1, 2018 06:45
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save killerchip/7054362d743496a57f123b4f77413342 to your computer and use it in GitHub Desktop.
Save killerchip/7054362d743496a57f123b4f77413342 to your computer and use it in GitHub Desktop.
Angular cheatsheet: Reactive Forms

Reactive Forms

A quick reference guide on how to setup.

How to setup

import ReactiveFormsModule

import { ReactiveFormsModule } from '@angular/forms';
@NgModule ({
  ...
  imports: [
    ReactiveFormsModule,
    ...
  ]
})

define a FormGroup

import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
...

export FormComponent {

  public userForm: FormGroup;
  public 
  
  constructor(
    private fb: FormBuilder
  ){
    this.userForm = this.fb.group({
      username: ['user1', Validators.required]    //default value = 'user1', Optional validator = required
    });
    
    this.username = this.userForm.controls['username'];   //optional. Allows easier reference in HTML template
    
  }
  
  public onSubmit(formValue: any) {
    console.log('You submitted: ', formValue);
  }
  

}

Create form and bind controls

<form [formGroup]="userForm"
  (ngSubmit)="onSubmit(userForm.value)"     
>

  <label for="usernameElm">Username</label>
  <input type="text"
    id="usernameElm"
    placeholder="enter username here"
    [formControl]="userForm.controls['username']"
  >
  
  <!-- 
    optionally you could bing the element to the Control property:
     [formControl]="username"
  -->

  <button type="submit">Submit</button>

</form>

Handling errors and validation

Checking whole form validity example

  <button [disabled]="!userForm.valid"
    type="submit>Submit</button>

Detecting errors in controls

  <input [class.error]="!userForm.controls['username'].valid"
  ...

Handling specific validation errors

  <div *ngIf="userForm.controls['username'].hasError('required')">
    You must enter a username
  </div>

Good practice: see if control is touched

  <!-- we are using the reference variable for leaner code -->
  
  <input [class.error]="!username.valid && username.touched"
  
  <div *ngIf="username.hasError('required') && username.touched"

Other validation options

Errors from FormGroup level

You can check for errors of specific field even in FormGroup level:

  console.log (userForm.hasError('required','username');  // FormGroup.hasError(errorKey, fieldKey)

Custom Validators

Create a function that accepts FormControl object as parameter and returns an error string map {errorKey: boolean} if the error is valid.

Define Validator Example: Not allow 'admin' as username.

private reservedUsernames (control: FormControl): { [string]: boolean } {
  if (control.value === 'admin') {
    return {reserved: true};
  }
}

Apply Validator

this.userForm = this.fb.group({
  username: ['', Validators.compose(
    [Validators.required, this.reservedUsernames]
  )]    
});

Check in HTML template

<div *ngIf="userForm.controls['username'].hasError('reserved')">
  Username reserved and cannot be used.
</div>

Monitor changes

There is an available Observable valueChanges in both FormGroup and FormControl classes.

this.userForm.valueChanges.subscribe(
  (value: any) => console.log('Form Value changed to', value)
);

this.userForm.controls['usernames'].valueChanges.subscribe(
  (value: string) => console.log('Current username: ', value);
);

2-way data bind

If you need to... you can bind an input control value to an external variable.

Component class:

public currentUsername: string;

//example of setting the value of currentUsername
  public suggest() {
    this.currentUsername = 'user'+Math.floor((Math.random() * 10) + 1);
  }

HTML template:

...
  <!-- ngModel binds the input element value to variable
  <input type="text"
    placeholder="enter username here"
    id="usernameElem"
    [formControl]="userForm.controls['username']"
    [(ngModel)]="currentUsername"
  >
  ...
  <!-- the currentUsername reflects the value of input element -->
  <div> Current Value: {{currentUser}}</div>
  
  <!-- setting the currentUsername reflects the value back to input element -->
  <button (click)="suggest()">Suggest a username</button>

Note: ngModel binds the input element value to variable. We still have to use [formControl] to bind the input element with the rest of our FormGroup and make it part of it (validation, etc).

Notes

  • When Angular sees [formGroup] in a <form> element, it does not automatically bind the ngForm FormGroup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment