#angular #angular2-forms
#угловой #angular2-формы
Вопрос:
Я пытаюсь создать форму, управляемую данными, с входными данными, поступающими от другого компонента, например:
<form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
<app-form-group [name]="name"></app-form-group>
<app-form-group [name]="email"></app-form-group>
<app-form-group [name]="other"></app-form-group>
</form>
app-form-group
Компонент будет выглядеть примерно так:
<div class="form-group">
<label class="col-md-2 control-label">{{Name}}</label>
<div class="col-md-9">
<input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
Проблема в том, что formControlName
требуется formGroup
директива, поэтому я получаю эту ошибку:
Error : Error in ./FormGroupComponent class FormGroupComponent - inline template:3:58 caused by: formControlName must be used with a parent formGroup directive.You'll want to add a formGroup
directive and pass it an existing FormGroup instance (you can create one in your class).
Есть ли какой-нибудь способ обойти эту проблему?
Комментарии:
1. Вам нужно будет реализовать свой собственный
ControlValueAccessor
, как указано здесь blog.thoughtram.io/angular/2016/07/27 /…
Ответ №1:
Вы должны использовать свою FormGroup [formGroup]="signupForm"
в app-form-group
компоненте.Вы можете использовать этот код :
<div class="form-group" [formGroup]="signupForm">
<label class="col-md-2 control-label">{{Name}}</label>
<div class="col-md-9">
<input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
Комментарии:
1. Как это может
signupForm
быть видно изapp-form-group
дочернего компонента? Разве вам не нужно передавать его в явном виде, как в ответе Бернхарда Хохгаттерера?2. Вы должны отправить «Signuoform» в качестве входных данных
Ответ №2:
Вы можете использовать свойство @Input, чтобы получить ссылку на подкомпонент:
app-form-group.ts:
@Input('group')
public signupForm: FormGroup;
app.html:
<form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
<app-form-group [name]="name" [group]="signupForm"></app-form-group>
<app-form-group [name]="name" [group]="signupForm"></app-form-group>
<app-form-group [name]="name" [group]="signupForm"></app-form-group>
</form>
app-form-group.html:
<div class="form-group" [formGroup]="signupForm">
<label class="col-md-2 control-label">{{Name}}</label>
<div class="col-md-9">
<input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
Для получения подробной информации ознакомьтесь с этим руководством: https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2
Ответ №3:
Если вы хотите реализовать пользовательский компонент для привязки данных к отдельному значению, правильный угловой способ сделать это — использовать подход, в котором родительское представление указывает либо [formControl]
или [formControlName]
.
<app-form-group formControlName="name"></app-form-group>
<app-form-group formControlName="email"></app-form-group>
<app-form-group formControlName="other"></app-form-group>
В вашем дочернем элементе управления вам необходимо выполнить следующее:
Сначала добавьте в свое @Component
объявление следующего поставщика, чтобы Angular знал, что ваш компонент может работать с [formControlName]
/ [formControl]
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CountrySelectorComponent),
multi: true
}
]
Затем класс вашего дочернего компонента должен реализовать ControlValueAccessor
интерфейс. Это должен быть полностью рабочий пример, если нет, то дайте мне знать, и я изменю код, я ввел его непосредственно в браузер.
@Component({
// Ensure [formControl] or [formControlName] is also specified
selector: '[formControl] app-form-group, [formControlName] app-form-group',
templateUrl: './country-selector.component.html',
styleUrls: ['./country-selector.component.scss'],
providers: [
{
// Provide the value accessor
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CountrySelectorComponent),
multi: true
}
]
})
export class CountrySelectorComponent implements ControlValueAccessor {
private value: any;
private hasHadFocus = false;
private hasNotifiedTouched = false;
private propagateChange: any = () => {};
private propogateTouched: any = () => {};
public changed(event: any) {
this.value = event.srcElement.value;
this.propagateChange(this.value);
}
/**
* Called when (focus) is triggered
*/
public focused() {
this.hasHadFocus = true;
}
/**
* Called when (blur) is triggered
*/
public blurred() {
if (this.hasHadFocus amp;amp; !this.hasNotifiedTouched) {
// Only notify once, and only if lost focus after a focus
this.hasNotifiedTouched = true;
this.propogateTouched();
}
}
/**
* Called when a new value is set via code
* @param obj
*/
writeValue(obj: any): void {
this.value = obj;
}
/**
* Register a call back to call when our value changes
* @param fn
*/
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
/**
* Register a call back to call when our value is first touched
* @param fn
*/
registerOnTouched(fn: any): void {
this.propogateTouched = fn;
}
}
Ваш app-form-group
шаблон будет выглядеть примерно так
<div class="form-group">
<label class="col-md-2 control-label">{{Name}}</label>
<div class="col-md-9">
<input class="form-control" (blur)="blurred()" focus="focussed()" change="changed($event)">
</div>
- Добавьте
[formGroup]="signupForm"
в каждый из вашихapp-form-group
экземпляров в главном представлении - Внедрите OnInit в свой
app-form-group
элемент управления. - Добавьте
private controlContainer: ControlContainer
в конструктор вашегоapp-form-group
компонента, чтобы Angular внедрил его - Добавьте
public form: FormGroup;
свойство к своемуapp-form-group
компоненту. -
В ngOnInit добавьте следующий код
это.form = this.ContainerControl.control;
В вашем app-form-group
шаблоне вы бы добавили [FormGroup] следующим образом
<div class="form-group" [formGroup]="form">
<label class="col-md-2 control-label">{{Name}}</label>
<div class="col-md-9">
<input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
Это метод, который требует наименьшего количества кода, и я бы рекомендовал его, когда вы хотите внедрить составные элементы управления, которые редактируют несколько фрагментов данных (например, адрес).
Из этого блога -> https://mrpmorris.blogspot.co.uk/2017/08/angular-composite-controls-formgroup-formgroupname-reactiveforms.html