Допустим, у нас есть адрес и мы хотим повторно использовать его в нескольких формах (например, человек, компания, ...) В Angular все компоненты, поэтому нам, вероятно, следует написать компонент.
Как лучше всего это сделать? Оказывается, все не так просто. Он должен инкапсулировать данные, а также проверять встроенные поля формы. Я нашел два решения проблемы:
1. Компонент настраиваемой формы
Что мне в нем не нравится: чрезмерно сложный, внутри подкомпонента все делегированный. При валидации вам понадобится какая-то «внутренняя форма», чтобы валидация работала. Элементы управления формы должны быть определены в родительском элементе, инкапсуляция на самом деле невозможна. Простой пример, см.: https://stackblitz.com/edit/angular-nested-form-custum-component-test
2. Компонент, который имеет два входа: FormGroup и form-submit-state.
Идея взята из https://medium.com/spektrakel-blog/angular2-building-nested-reactive-forms-7978ecd145e4
Намного проще, чем компонент пользовательской формы. Нам нужно предоставить FormGroup, которая построена вне вложенного компонента. Если мы хотим отображать ошибки проверки «onSubmit», нам также необходимо предоставить дочернему компоненту «отправленное состояние» формы. Простой пример, см. https://stackblitz.com/edit/angular-nested-formcomponent-test
Есть комментарии или лучшие идеи по решению проблемы?
Вы можете поддерживать инкапсуляцию, передав FormGroup вложенному элементу управления с начальным значением и позволяя вложенному элементу управления определять свою собственную внутреннюю группу формы вместе с любыми валидаторами.
app.component.html
<nested-form-cmp
init = "foo"
[formSubmitted] = "f.submitted"
[grp] = "myForm">
</nested-form-cmp>
AppComponent нужно будет только инициализировать свои собственные данные формы:
export class AppComponent {
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
name: ['', Validators.required]
})
}
submit(form: NgForm) {
console.info("Reactive Form submitted: " + form.submitted);
}
}
вложенный-form.component.html
Вложенный компонент будет отвечать за создание своей собственной вложенной FormGroup и инициализацию ее с помощью валидаторов:
<div [formGroup] = "grp">
<div formGroupName = "innerGrp">
<label>
Inner name:
<input formControlName = "name2" type = "text" id = "outer"/>
</label>
<span class = "error" *ngIf = "(formSubmitted || grp.get('innerGrp.name2').touched) && grp.get('innerGrp.name2').hasError('required')">
Inner name is required
</span>
</div>
</div>
вложенный-form.component.ts
export class NestedFormComponent implements OnInit{
// The FormGroup built in the parent
@Input() public grp: FormGroup;
@Input() public init: string;
// Needed, because the FormGroup does not get the forms submitted state
@Input() public formSubmitted: boolean;
constructor(private fb: FormBuilder){
}
ngOnInit() {
this.grp.setControl('innerGrp', this.fb.group({
name2: [this.init, Validators.required]
}))
}
}
Я думаю, что наличие компонента, который инкапсулирует группу форм, а также любые валидаторы формы, является допустимым вариантом использования. Я мог видеть ценность в наличии компонента «Адрес», который имеет несколько полей и поддерживает передачу модели адреса, что я мог бы повторно использовать его из разных мест.
Похоже, хорошее улучшение для лучшей инкапсуляции. Согласны ли вы, что компоненты пользовательской формы не подходят для компонентов, которые инкапсулируют часть формы? Конечно, если нужно создать библиотеку, которая инкапсулирует функциональность, как правило, с одним значением (например, настраиваемый указатель даты), тогда подойдут компоненты настраиваемой формы.