Формы. Шаблонный подход.

Создание формы и регистрация контроллеров

Для работы с формами нужно добавить FormsModule в импорты модуля. Аpp.modules.ts:

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

Добавить директиву ngModel в input и select формы, чтобы указать, что данный инпут это контроллер формы:

<input 
type="text"
id="username"
class="form-control"
name="username"
ngModel
>

Чтобы использовать директиву ngModel у поля обязательно должен быть указан атрибут name. Иначе в консоли будет ошибка.

Для назначения обработчика используется событие ngSubmit:

<form (ngSubmit)="onSubmit()">

Для того, чтобы передать в обработчик данные формы можно использовать локальную ссылку #:

<form (ngSubmit)="onSubmit(formdata)" #formdata>

Чтобы передать в обработчик не просто локальную ссылку, а js объект, представляющий данные формы и связанный с ней, нужно воспользоваться директивой NgForm:

<form (ngSubmit)="onSubmit(formdata)" #formdata="ngForm">

Доступ к форме с помощью @ViewChild

Если нужно получить данные формы до момента отправки, то можно воспользоваться @ViewChild.

Шаблон:

<form (ngSubmit)="onSubmit()" #formdata="ngForm">

Компонент:

import { Component, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';

@Component({
//...
})
export class AppComponent {
@ViewChild('formdata') myForm: NgForm;
//...
onSubmit(form: NgForm) {
console.log(this.myForm);
}
}

Валидация форм

Angular поддерживает специальные директивы, позволяющие валидировать пользовательский ввод.

  • required - обязательное для заполнения поле
  • email - указатель, что поле формата email адрес.

Пример использования данных директив:

<input 
type="email"
id="email"
class="form-control"
name="email"
ngModel
required
email
>

Angular динамически устанавливает css классы у проверяемых инпутов. Это позволяет создавать дизайн для различных состояний.

Список встроенных валидаторов.

ngNativeValidate (добавляется в поле шаблона) - директива переключает Angular в режим стандартной HTML5 валидации.

Валидация регулярным выражением

В input шаблона добавить паттерн регулярного выражения, например: [pattern]="'^[1-9][0-9]*$'".

Или короткий вариант записи: pattern="^[1-9][0-9]*$".

Использование состояний формы

Скрытие кнопки, если форма не прошла валидацию:

<form (ngSubmit)="onSubmit(formdata)" #formdata="ngForm">
<!-- ... -->
<button
class="btn btn-primary"
type="submit"
[disabled]="!formdata.valid"
>

Submit
</button>
</form>

Выделение инпута красной рамкой. В стилях шаблона:

input.ng-invalid.ng-touched {
border: 1px solid red;
}

Вывод ошибок валидации

<input 
type="email"
id="email"
class="form-control"
name="email"
ngModel
required
email
#email="ngModel"
>

<span *ngIf="!email.valid && email.touched">
Enter valid email
</span>

Значение по умолчанию

С помощью [ngModel]="'value_name'" можно установить дефолтное значение. Если используется значение переменной компонента, то вторые кавычки не нужны: [ngModel]="value_name_from_component".

<select 
id="secret"
class="form-control"
name="secret"
[ngModel]="'teacher'"
>

<option value="pet">Your first Pet?</option>
<option value="teacher">Your first teacher?</option>
</select>

ngModel и двухстороннее связывание

<div class="form-group">
<textarea
name="questionAnswer"
rows="3"
class="form-control"
[(ngModel)]="answer"
>

</textarea>
<p>You type: {{answer}}</p>
</div>

Переменная answer должна быть определена в компоненте.

Группировка элементов

Несколько элементов могут быть сгруппированы с помощью директивы ngModelGroup. Для этого нужно обернуть div'ом несколько элементов формы и указать у данного блока эту директиву.

Локальная ссылка создается по шаблону #link_name="ngModelGroup". Это позволяет получить доступ к js объекту.

Сгруппировав несколько элементов формы и создав локальную ссылку, мы можем использовать js объект для различных целей, например, для вывода предупреждения о том, что какой-либо элемент группы не прошел валидацию:

<p *ngIf="!link_name.valid && link_name.touched">
Не верно заполнена группа
</p>

Радиокнопки (Radiobuttons)

В компоненте создадим переменную:

genders = ['male', 'female'];

В шаблоне:

<div class="radio" *ngFor="let gender of genders">
<label>
<input
type="radio"
name="gender"
ngModel
[value]="gender"
required
>

{{gender}}
</label>
</div>

Установка значения формы из компонента

У NgForm есть метод setValue(), который принимает значения всех полей формы и устанавливает их:

@ViewChild('formdata') myForm: NgForm;
//...
suggestUserName() {
const suggestedName = 'Superuser';
this.myForm.setValue({
username: suggestedName,
email: '',
secret: 'pet',
questionAnswer: '',
gender: 'male',
});
}

Чтобы изменить не все поля формы, а только часть, используется другой метод:

@ViewChild('formdata') myForm: NgForm;
//...
this.myForm.form.patchValue({
username: suggestedName,
gender: 'male',
});

Использование данных формы

Создадим объект user и запишем в него данные формы, на событие отправки формы.

user = {
name: '',
mail: '',
secretQuestion: '',
answer: '',
gender: '',
}

onSubmit() {
this.submitted = true;
this.user.name = this.myForm.value.username;
this.user.mail = this.myForm.value.email;
this.user.secretQuestion = this.myForm.value.secret;
this.user.answer = this.myForm.value.questionAnswer;
this.user.gender = this.myForm.value.gender;
}

Если данные в форме сгруппированы, то необходимо указывать группу, например:

this.user.name = this.myForm.value.userData.username;
this.user.mail = this.myForm.value.userData.email;

Сброс формы

@ViewChild('formdata') myForm: NgForm;
//...
this.myForm.reset();

В функцию reset() можно передать объект, аналогичный тому, который передается в setValue(), чтобы сбросить поля в определенные значения.

Источник – курс «Angular 5 the complete guide», Maximilian Schwarzmüller
Редактировать на GitHub