Во-первых, существует три типа форм - FormControl
, FormGroup
и FormArray
- все они наследуются от AbstractControl
.
Когда вы используете Reactive Forms для проверки и включаете formGroupName
, formControlName
или formArrayName
в шаблон компонента, вы фактически декларативно определяете карту между деревом управления формой и корневой FormGroup
моделью.
Например, с учетом следующего шаблона:
<div [formGroup]="formGroup">
<div formGroupName="personalInfo">
First Name: <input type="text" formControlName="firstName"><br />
Last Name: <input type="text" formControlName="lastName"><br />
</div>
<div formArrayName="cities">
Top cities: <input *ngFor="let city of cities; index as i" type="text" [formControlName]="i">
</div>
</div>
Вы декларативно настраиваете карту формы для сбора информации, которая в конечном итоге создаст объект JSON в определенном формате. Например, с учетом приведенной выше модели формы, formGroup.value
вернет:
{
"personalInfo": {
"firstName: 'John',
"lastName: 'Smith'
},
"cities": [
"New York",
"Winnipeg",
"Toronto"
]
}
После того, как вы объявили структуру вашей группы форм в шаблоне, вам необходимо обязательно создать соответствующие formGroup
, formControl
и formArray
в вашем классе компонентов. При настройке каждой формы у вас есть возможность настроить дополнительные параметры:
1. Initial Form Value
2. Array of synchronous validators
3. Array of asynchronous validators
Это относится к любому из абстрактных элементов управления.
Вот как будет выглядеть соответствующая модель formGroup с использованием приведенного выше шаблона:
export class AppComponent {
firstName: string,
lastName: string;
cities: string[];
@Input() formGroup: FormGroup;
constructor(private fb: FormBuilder) {
// setup initial values
this.cities = ['New York', 'Winnipeg', 'Toronto'];
this.firstName = 'John';
this.lastName = 'Smith';
// create a formGroup that corresponds to the template
this.formGroup = fb.group({
firstName: [this.firstName, Validators.required],
lastName: [this.lastName, Validators.required],
cities: fb.array(this.cities.map(t=> fb.control(t, Validators.required)))
})
}
}
Для привязки к любому из флагов проверки формы вы можете использовать корень formGroup
и строку пути (которая поддерживает точки), чтобы найти определенную группу, элемент управления или массив.
Например:
<div *ngIf="formGroup.get('firstName').errors.required">First Name is Required</div>
Надеюсь, это проясняет.
[Изменить]
Еще лучше, учитывая, что Reactive Forms - это декларативная настройка модели в шаблоне и обязательное сопоставление одной и той же модели в классе компонентов, вам следует рассмотреть возможность определения модели JSON и ее использования вместо этого.
Например, предположим, что у нас есть пользовательская модель MyModel
, которая имеет свойство firstName
, свойство lastName
и свойство cities
. Класс компонента будет выглядеть следующим образом:
export class AppComponent {
@Input() model: MyModel;
@Output() modelChange: EventEmitter<MyModel>;
@Input() formGroup: FormGroup;
constructor(private fb: FormBuilder) {
this.model = new EventEmitter<MyModel>();
// create a formGroup that corresponds to the template
this.formGroup = fb.group({
firstName: [this.model.firstName, Validators.required],
lastName: [this.model.lastName, Validators.required],
cities: fb.array(this.model.cities.map(t=> fb.control(t, Validators.required)))
});
}
onSubmit() {
if (this.formGroup.valid) {
this.model = this.formGroup.value;
this.modelChange.next(this.model);
}
}
}