Skip to content

Instantly share code, notes, and snippets.

@ivankisyov
Last active April 9, 2019 05:25
Show Gist options
  • Save ivankisyov/8ec674a0d6bc67f0ba772e552d222840 to your computer and use it in GitHub Desktop.
Save ivankisyov/8ec674a0d6bc67f0ba772e552d222840 to your computer and use it in GitHub Desktop.
[Angular] Reactive forms

[Angular] Reactive forms

Simple reactive form example

export class YourComponent implements OnInit {
  myReactiveForm = new FormGroup({
    username: new FormControl("", Validators.required),
    password: new FormControl("", Validators.required)
  });

  constructor() {}

  ngOnInit() {}

  get username() {
    return this.myReactiveForm.get("username");
  }
}

<form [formGroup]="myReactiveForm">
  <div class="form-group">
    <label for="username">Username</label>
    <input
      type="text"
      class="form-control"
      id="username"
      formControlName="username"
      placeholder="Enter username"
    />
    <div
      *ngIf="username.touched && username.invalid"
      id="emailHelp"
      class="alert alert-danger"
    >
      username is required
    </div>
  </div>
  <div class="form-group">
    <label for="password">Password</label>
    <input
      type="password"
      formControlName="password"
      class="form-control"
      id="password"
      placeholder="Password"
    />
  </div>

  <button type="submit" class="btn btn-primary">Submit</button>
</form>

using mutliple validators

 myReactiveForm = new FormGroup({
    username: new FormControl("", [
      Validators.required,
      Validators.minLength(3)
    ]),
    password: new FormControl("", Validators.required)
  });
<div
  *ngIf="username.touched && username.invalid"
  class="alert alert-danger"
>
  <div *ngIf="username.errors.required">
    username is required
  </div>
  <div *ngIf="username.errors.minlength">
    username minlength must be at least
    {{ username.errors.minlength.requiredLength }}
    characters
  </div>
</div>

creating and using custom validation

// username.validators.ts

import { AbstractControl, ValidationErrors } from "@angular/forms";

export class UsernameValidators {
  static cannotContainSpace(control: AbstractControl): ValidationErrors | null {
    if ((control.value as string).indexOf(" ") >= 0) {
      return {
        cannotContainSpace: true
      };
    }

    return null;
  }
}
 myReactiveForm = new FormGroup({
  username: new FormControl("", [
    Validators.required,
    Validators.minLength(3),
    UsernameValidators.cannotContainSpace
  ]),
  password: new FormControl("", Validators.required)
});
<div *ngIf="username.errors.cannotContainSpace">
  username cannot contain space
</div>

Creating and using custom async validation

static shouldBeUnique(
    control: AbstractControl
  ): Promise<ValidationErrors | null> {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (control.value === "batman") {
          resolve({
            shouldBeUnique: true
          });
        } else {
          resolve(null);
        }
      }, 2000);
    });
  }
 myReactiveForm = new FormGroup({
  username: new FormControl(
    "",
    [
      Validators.required,
      Validators.minLength(3),
      UsernameValidators.cannotContainSpace
    ],
    UsernameValidators.shouldBeUnique
  ),

  password: new FormControl("", Validators.required)
});
<div *ngIf="username.errors.shouldBeUnique">
  username is already taken
</div>

displaying info message while async validation is in progress

<div *ngIf="username.pending">
  checking for uniqueness...
</div>

Validation on submit

 login() {
    this.myReactiveForm.setErrors({
      loginFailed: true
    });
  }
<form [formGroup]="myReactiveForm" (ngSubmit)="login()">
    <div *ngIf="myReactiveForm.errors" class="alert alert-danger">
      login failed
    </div>

Nested formGroups

<form [formGroup]="myReactiveForm" (ngSubmit)="login()">
        <div formGroupName="profile">
myReactiveForm = new FormGroup({
    profile: new FormGroup({
      username: new FormControl(
        "",
        [
          Validators.required,
          Validators.minLength(3),
          UsernameValidators.cannotContainSpace
        ],
        UsernameValidators.shouldBeUnique
      ),

      password: new FormControl("", Validators.required)
    })
  });

Using FormArray

myReactiveFormWithFormArray = new FormGroup({
    topics: new FormArray([])
  });
addTopic(topic: HTMLInputElement) {
    this.topics.push(new FormControl(topic.value));
    console.log(this.topics);
    topic.value = "";
  }

  get topics() {
    return this.myReactiveFormWithFormArray.get("topics") as FormArray;
  }
<form [formGroup]="myReactiveFormWithFormArray">
  <div class="form-group">
    <label for="username">add topic:</label>
    <input
      type="text"
      class="form-control"
      placeholder="Enter new topic"
      #topic
      (keyup.enter)="addTopic(topic)"
    />
    <hr />
    <ul class="list-group">
      <li class="list-group-item" *ngFor="let topic of topics.controls">
        {{ topic.value }}
      </li>
    </ul>
  </div>
</form>

Using FormBuilder

control: FormControl;

constructor(private fb: FormBuilder) {
  this.control = fb.group({
    name: ['', Validators.required],
    address: fb.group({
      street: [],
      city: []
    }),
    topics: fb.array([])
  });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment