Ответ 1
Это несколько месяцев спустя, но я подумал, что предоставил свое решение на основе этого учебника. Суть его в том, что вам намного легче управлять, как только вы меняете способ приближения к формам.
Сначала используйте ReactiveFormsModule
вместо или в дополнение к нормальному FormsModule
. С реактивными формами вы создаете свои формы в своих компонентах/сервисах, а затем подключаете их к своей странице, а не страницу, генерирующую форму. Это немного больше кода, но это намного более проверяемо, намного более гибко, и насколько я могу сказать, лучший способ сделать много нетривиальных форм.
Конечный результат будет выглядеть примерно так: концептуально:
-
У вас есть одна база
FormGroup
с любымиFormControl
экземплярами, необходимыми для всей формы. Например, как и в учебнике, к которому я привязался, давайте скажем, что вам нужна форма, в которой пользователь может ввести свое имя один раз, а затем любое количество адресов. Все одноразовые входы поля будут в этой базовой форме. -
Внутри экземпляра
FormGroup
будет один или несколько экземпляровFormArray
. AFormArray
- это в основном способ группировать несколько элементов управления вместе и перебирать их. Вы также можете поместить несколько экземпляровFormGroup
в свой массив и использовать их как по существу "мини-формы", вложенные в вашу большую форму. -
Встраивая несколько экземпляров
FormGroup
и/илиFormControl
в динамическийFormArray
, вы можете управлять достоверностью и управлять формой как одной, большой реактивной частью, состоящей из нескольких динамических частей. Например, если вы хотите проверить, действителен ли каждый отдельный вход, прежде чем разрешить пользователю отправлять данные, действительность одной подформы будет "пузыриться" до формы верхнего уровня, а вся форма становится недействительной, что упрощает управлять динамическими входами. -
Поскольку
FormArray
является, по существу, оберткой вокруг интерфейса массива, но для частей формы, вы можете в любое время удалять, удалять, вставлять и удалять элементы управления без повторного создания формы или выполнения сложных взаимодействий.
В случае, если учебник, с которым я связан, идет вниз, вот пример кода, который вы можете реализовать самостоятельно (мои примеры используют TypeScript), которые иллюстрируют основные идеи:
Код базового компонента:
import { Component, Input, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'my-form-component',
templateUrl: './my-form.component.html'
})
export class MyFormComponent implements OnInit {
@Input() inputArray: ArrayType[];
myForm: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
let newForm = this.fb.group({
appearsOnce: ['InitialValue', [Validators.required, Validators.maxLength(25)]],
formArray: this.fb.array([])
});
const arrayControl = <FormArray>newForm.controls['formArray'];
this.inputArray.forEach(item => {
let newGroup = this.fb.group({
itemPropertyOne: ['InitialValue', [Validators.required]],
itemPropertyTwo: ['InitialValue', [Validators.minLength(5), Validators.maxLength(20)]]
});
arrayControl.push(newGroup);
});
this.myForm = newForm;
}
addInput(): void {
const arrayControl = <FormArray>this.myForm.controls['formArray'];
let newGroup = this.fb.group({
/* Fill this in identically to the one in ngOnInit */
});
arrayControl.push(newGroup);
}
delInput(index: number): void {
const arrayControl = <FormArray>this.myForm.controls['formArray'];
arrayControl.removeAt(index);
}
onSubmit(): void {
console.log(this.myForm.value);
// Your form value is outputted as a JavaScript object.
// Parse it as JSON or take the values necessary to use as you like
}
}
Подкомпонентный код: (по одному для каждого нового поля ввода, чтобы сохранить чистоту)
import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';
@Component({
selector: 'my-form-sub-component',
templateUrl: './my-form-sub-component.html'
})
export class MyFormSubComponent {
@Input() myForm: FormGroup; // This component is passed a FormGroup from the base component template
}
Базовый компонент HTML
<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
<label>Appears Once:</label>
<input type="text" formControlName="appearsOnce" />
<div formArrayName="formArray">
<div *ngFor="let control of myForm.controls['formArray'].controls; let i = index">
<button type="button" (click)="delInput(i)">Delete</button>
<my-form-sub-component [myForm]="myForm.controls.formArray.controls[i]"></my-form-sub-component>
</div>
</div>
<button type="button" (click)="addInput()">Add</button>
<button type="submit" [disabled]="!myForm.valid">Save</button>
</form>
Подкомпонентный HTML
<div [formGroup]="form">
<label>Property One: </label>
<input type="text" formControlName="propertyOne"/>
<label >Property Two: </label>
<input type="number" formControlName="propertyTwo"/>
</div>
В приведенном выше коде у меня в основном есть компонент, который представляет базу формы, а затем каждый подкомпонент управляет собственным экземпляром FormGroup
внутри FormArray
, расположенным внутри базы FormGroup
. Базовый шаблон проходит по подгруппе в подкомпонент, а затем вы можете обрабатывать валидацию для всей формы динамически.
Кроме того, это делает тривиальным переупорядочить компонент, стратегически вставляя и удаляя их из формы. Он работает с (по-видимому) с любым количеством входов, поскольку они не конфликтуют с именами (большой недостаток форм, управляемых шаблонами, насколько мне известно), и вы по-прежнему сохраняете почти автоматическую проверку. Единственным "недостатком" этого подхода является, помимо написания немного больше кода, вам нужно заново изучить, как работают формы. Тем не менее, это откроет возможности для гораздо более крупных и динамичных форм, когда вы продолжаете.
Если у вас есть какие-либо вопросы или вы хотите указать некоторые ошибки, продолжайте. Я только что набрал вышеуказанный код, основываясь на том, что я сделал сам на прошлой неделе, с измененными именами и другими разным. свойства оставлены, но это должно быть просто. Единственное существенное различие между приведенным выше кодом и моей собственностью заключается в том, что я переместил все формы в отдельную службу, вызванную из компонента, так что она немного менее беспорядочна.