Введение в реактивные формы Angular (Reactive Forms Angular)

Angular предоставляет два способа работы с формами: шаблонные формы и реактивные формы, последние еще называют формами управляемые моделью. Шаблонные формы используются по умолчанию в Angular для работы с формами, директивы в шаблонах используются для построения внутреннего представления формы. В реактивных формах вы создаете собственное представления формы в классе компоненте.
Хотя реактивные формы могут показаться сложными при начале работы с ними, они позволяют сделать формы более гибкими и помогают держать логику внутри класса компонента и делают шаблоны более простыми.
Примеры случаев где реактивные формы очень удобны:

  • написания кастомных валидаторов
  • динамическое изменение валидации
  • динамическое добавления элементов формы

Давайте рассмотрим как интегрировать реактивные формы в ваше Angular приложение.

Импорт модуля ReactiveFormsModule

Для работы с реактивными формами, мы будем использовать модуль ReactiveFormsModule вместо FormsModule.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';

@NgModule({
  // ...
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    HttpModule
  ],
  // ...
})
export class AppModule { }

Пример шаблона: formGroup, ngSubmit & formControlName

При использовании реактивных форм вся логика содержится в классе компонента, поэтому код шаблона выглядит очень простым:

<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)">
  <input formControlName="login" placeholder="Your email">
  <input  type="password" formControlName="password" placeholder="Your password">
  <button type="submit">Submit</button>
</form>

Если вы используете Angular 2.x, добавьте директиву novalidate в тег формы, так как Angular переопределять HTML5 валидацию. В Angular 4+ директива novalidate добавляет автоматически.
Рассмотрим директивы formGroup, ngSubmit & formControlName детальней

  • formGroup — форма будет трактоваться как FormGroup в классе компоненте. Директива formGroup позволяет дать имя форме.
  • ngSubmit: Позволяет зарегистрировать обработчик сабмита формы
  • formControlName: Каждое поле формы должно иметь директиву formControlName с значением имени, которое будет
    использоваться в классе компоненте

Класс компонент

В классе компоненте мы определим группу формы и каждое поле в нашей группе.
При создании FormControl можно задать начальное значения поля.
Обратите внимания как имена группы формы и имена полей совпадают с теми которые мы использовали в шаблоне. Также необходимо инициализировать форму в методе жизненного цикла ngOnInit

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

@Component({
  // ...
})
export class AppComponent implements OnInit {
  myForm: FormGroup;

  ngOnInit() {
    this.myForm = new FormGroup({
      login: new FormControl(''),
      password: new FormControl('')
    });
  }

  onSubmit(form: FormGroup) {
    console.log('Valid?', form.valid); // true or false
    console.log('Login', form.value.login);
    console.log('Password', form.value.password);
  }
}

FormBuilder

Мы можем упростить код с помощью класса FormBuilder, который позволяет нам отказаться от ручного создания элементов FormControl и FormGroup.

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

@Component({
  // ...
})
export class AppComponent implements OnInit {
  myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      login: '',
      password: ''
    });
  }

  // ...
}

Валидация

Добавления валидации в форму происходит очень просто. Нужно импортировать класс Validators и передать массив как начальное значения поля формы.
Первое значения в массиве отвечает за начальное значения поля второе отвечает за валидаторы. Кроме того можно передать несколько валидаторов.

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  // ...
})
export class AppComponent implements OnInit {
  myForm: FormGroup;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
  this.myForm = this.fb.group({
    login: ['', [Validators.required, Validators.pattern('[a-z0-9.@]*')]],
    password: ['', [Validators.required, Validators.minLength(6)]]
  });
  }
}

Получения доступа к значения элементов формы и их валидности в шаблоне

В шаблоне формы мы можем получить доступ к каждому элементу формы и состоянию их валидности, а также валидности всей группы

<form [formGroup]="myForm" (ngSubmit)="onSubmit(myForm)">
  <input formControlName="login" placeholder="Your login">

  <p>Your login: {{ myForm.get('login').value }}</p>
  <div *ngIf="myForm.get('login').hasError('required')">
    Oops, please provide a login!
  </div>

  <input formControlName="password" placeholder="Your password">

  <div *ngIf="myForm.controls.email.hasError('minLength')">
    Oops, password too short!
  </div> 

  <button type="submit" [disabled]="myForm.invalid">
    Send
  </button>
</form>

Обратите внимания на то как можно получить доступ как с myForm.get(‘login’) так и myForm.controls.login, также мы можем получить доступ к ошибкам с помощью .hasError(‘required’) или .errors.required. Оба способы аналогичны и это дела вкуса что использовать

Также мы делаем кнопку отправки формы неактивной если форма не валидна.

Заключения

В этой статье сделано введения по работе с реактивными формами в Angular, более детальное описания можно найти в официальной документации. https://angular.io/docs/ts/latest/guide/reactive-forms.html