меню

Конфигурация реактивной формы

При реактивном подходе конфигурация формы происходит в компоненте, а не в шаблоне.

app.module.ts:

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

app.component.ts:

 
//...
import { FormControl, FormGroup } from '@angular/forms';
//...
export class AppComponent implements OnInit {
//...
testForm: FormGroup;
ngOnInit() {
    this.testForm = new FormGroup({
        'name': new FormControl(null),
        'email': new FormControl(null),
        'gender': new FormControl('male'),
    });
}

    onSubmit() {
    console.log(this.testForm);
}
  

app.component.html:

 
<form 
  [formGroup]="testForm"
  (ngSubmit)="onSubmit()"
>
  

Валидация реактивной формы

Реактивная форма конфигурируется из компонента. Для того, чтобы добавить валидацию, в конструктор объекта FormControl добавляется второй параметр - объект или массив объектов статичного класса Validators.

app.component.ts:

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

ngOnInit() {
    this.testForm = new FormGroup({
      'name': new FormControl(null, Validators.required),
      'email': new FormControl(null, [Validators.required, Validators.email]),
      'gender': new FormControl('male'),
    });
}
  

Работа с состояниями формы

В компоненте определена переменная testForm класса FormGroup, связанная с формой <form [formGroup]="testForm") ... >, тогда:

 
<input
    type="text"
    id="name"
    class="form-control"
    formControlName="name"
>
<span 
    class="help-block"
    *ngIf="!testForm.get('name').valid && testForm.get('name').touched"
>
    Please, enter yor name
</span>
  

Группировка полей реактивной формы

Поля группируются в объекте реактивной формы:

 
this.testForm = new FormGroup({
    'userData': new FormGroup({
        'name': new FormControl(null, Validators.required),
        'email': new FormControl(null, [Validators.required, Validators.email]),
    }),
    'gender': new FormControl('male'),
});
 

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

  
<form 
  [formGroup]="testForm"
  (ngSubmit)="onSubmit()"
>
  <div formGroupName="userData">
      <div class="form-group">
        <label for="name">Username</label>
        <input
          type="text"
          id="name"
          class="form-control"
          formControlName="name"
        >
          <span 
            class="help-block"
            *ngIf="!testForm.get('userData.name').valid && testForm.get('userData.name').touched"
          >
            Please, enter yor name
          </span>
        </div>
        <div class="form-group">
          <label for="email">email</label>
          <input
            type="text"
            id="email"
            class="form-control"
            formControlName="email">
        </div>
      </div>
  <div class="radio" *ngFor="let gender of genders">
      <label>
        <input
            type="radio"
            [value]="gender"
            formControlName="gender"
        >
        {{ gender }}
      </label>
  </div>
  <button class="btn btn-primary" type="submit">Submit</button>
</form>
 

FormArray, динамическое добавление полей

Компонент:

  
import { FormControl, FormGroup, Validators, FormArray } from '@angular/forms';
//...
        this.testForm = new FormGroup({
        //...
        'hobbies': new FormArray([])
        });
    //...
    onAddHobbie() {
        const control = new FormControl(null, Validators.required);
        (this.testForm.get("hobbies")).push(control);
    }
}
  

Шаблон:

  
<div formArrayName="hobbies">
    <h4>your hobbies</h4>
    <button 
    class="btn btn-default" 
    type="button"
    (click)="onAddHobbie()">
        add hobbie
    </button>
    <div 
        class="form-group"
        *ngFor="let hobbyControl of testForm.get('hobbies').controls; let i = index;">
        <input 
            type="text" 
            class="form-control"
            [formControlName]="i">
    </div>
</div>
  

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

Создадим валидатор, запрещающий некоторый имена. Внесем следующие доработки в компонент.

Добавим массив запрещенных имен:

 
forbiddenNames = ['Test', 'Hacker', 'Spammer'];
 

Валидатор - это функция. Создадим кастомный валидатор:

 
validateName(control: FormControl): {[s: string]: boolean} {
    if (this.forbiddenNames.indexOf(control.value) > -1) {
      return {'nameIsForbidden': true}
    } else {
      return null;
    }
}
 

Добавим кастомный валидатор к полю формы:

  
ngOnInit() {
  this.testForm = new FormGroup({
    'userData': new FormGroup({
      'name': new FormControl(null, [Validators.required, this.validateName.bind(this)]),
      //...
  

Кастомный валидатор необходимо привязывать к контексту с помощью .bind(this).

Вывод ошибок

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

 
<div class="form-group">
    <label for="name">Username</label>
    <input
        type="text"
        id="name"
        class="form-control"
        formControlName="name"
    >
    <span 
        class="help-block"
        *ngIf="!testForm.get('userData.name').valid && testForm.get('userData.name').touched"
    >
        <span *ngIf="testForm.get('userData.name').errors['nameIsForbidden']">
            This name is forbidden
        </span>
        <span *ngIf="testForm.get('userData.name').errors['required']">
            This name is required
        </span>
    

 

Асинхронная валидация

Добавим асинхронную валидацию для email:

  
this.testForm = new FormGroup({
    'userData': new FormGroup({
      'email': new FormControl(null, [Validators.required, Validators.email], this.asincValidateEmail),
      
      //...
asincValidateEmail(control: FormControl): Promise<any> | Observable<any> {
const promise = new Promise<any>((resolve, reject) => {
    setTimeout(()=>{
    if (control.value === "q@q") {
        resolve({'emailIsForbidden': true});  
    } else {
        resolve(null);
    }
    },
    1000);
});
return promise;
}
 

Подписка на изменение статуса или значения форм

В ngOnInit:

 
this.signupForm.valueChanges.subscribe(
    (value) => console.log(value)
);
this.signupForm.statusChanges.subscribe(
    (status) => console.log(status)
);
 

Полная и частичная установка значений формы

Полная:

  
this.testForm.setValue({
    'userData': {
      'name': 'Test',
      'email': 'test@test.com'
    },
    'gender': 'male',
    'hobbies': []
});
 

Частичная:

 
this.testForm.patchValue({
  'userData': {
    'name': 'Test2',
  }
});
 

Сброс формы:

 
this.testForm.reset();
  

Возможно, вам будет интересно

Инкапсуляция стилей и ссылки

Режимы инкапсуляции стилей, локальная ссылка в шаблоне Angular. Доступ к шаблону и DOM из компонента с помощью @ViewChild и @ContentChild.

Route. Вынос настроек роутера

Пример переноса роутинговой конфигурации Angular5 в отдельный файл

Observable. Subscribe и Unsubscribe

Stream и работа с Observable в Angular. Пример отписки в ngOnDestroy()

ng-content

Использование тега ng-content и размещения верстки из шаблона в теге вызова компонента в Angular

Оформление заявки

Документы на создание сайта

Изучите наше коммерческое предложение, заполните БРИФ и отправьте его на почту maxidebox@list.ru. Изучив все пожелания из БРИФ-а, обратным ответом оповестим Вас по стоимости разработке, ответим на вопросы.

КП на создание сайта Коммерческое предложение на созданеи сайта

Мы берем на себя ответственность за все стадии работы и полностью избавляем клиентов от забот и необходимости вникать в тонкости.

Скачать БРИФ (акета) на создание сайта Скачать БРИФ (акета) на создание сайта

Зополните у БРИФ-а все необходимые поля. Сделайте краткое описание к каждому из пунктов анкеты, привидите примеры в соответсвующий пунктах - это позволит лучше понять Ваши ожидания и требования к сайту