我必须创建一个表单,并且我想更清楚地了解组件
形式的主要思想是:
FormComponent | > FieldComponent | > Form的InputComponent
所以我有PartnerFormComponent:
HTML:
<form [formGroup]="partnerForm" (ngSubmit)="save()">
<!--<legal-information
[(partner)]="partner" [(partnerConfiguration)]="partnerConfiguration" ></legal-information>-->
<combo-billing-entity [(formGroup)]="partnerForm" [(partner)]="partner" [(partnerConfiguration)]="partnerConfiguration"></combo-billing-entity>
<div class="buttons_form">
<button class="save_button_form" type="submit" [disabled]="!partnerForm.valid">
Add
</button>
<a class="btn-floating btn-large waves-effect waves-light green"
routerLink="/partners">
<i class="material-icons">Cancel</i>
</a>
</div>
</form>
和ts:
@Component({
selector: 'partner-form',
templateUrl: './partner-form.component.html',
styleUrls: ['./partner-form.component.css'],
entryComponents:[LegalInformationComponent]
})
export class PartnerFormComponent implements OnInit {
private partnerForm: FormGroup;
title: string;
partner: Partner = new Partner();
partnerConfiguration: PartnerConfiguration = new PartnerConfiguration();
constructor(
private router: Router,
private route: ActivatedRoute,
private partnerService: PartnerService
) { }
ngOnInit() {
var id = this.route.params.subscribe(params => {
var id = params['id'];
if (!id)
return;
.....
});
}
然后从组件我有html Combo:
<div class="components_situation">
<div class="field_form_title">
{{title}} <span class="is_required_form" [hidden]="!isRequired">*</span>
</div>
<div [formGroup]="formGroup" >
<select id="billingEntity" [(ngModel)]="partnerConfiguration.fakeBillingEntity"
formControlName="billingEntity"
[class.invalid]="form.controls['billingEntity'].touched && !form.controls['billingEntity'].valid"
>
<option disabled hidden [value]="selectUndefinedOptionValue">-- select --</option>
<option *ngFor="let obj of billingEntities" [value]="obj.value" >{{obj.name}}</option>
</select>
</div>
<div class="some_explanation_form_field">{{someExplanation}}</div>
</div>
和TS:
import {Component, Input, OnInit} from "@angular/core";
import {CommonFieldFormComponent} from "../../common-field-form-component";
import {BillingService} from "../../../../../../services/billing/billing.service";
import {BillingEntitity} from "../../../../../../model/billing_entity";
import {FormBuilder, FormGroup, Validators} from "@angular/forms";
@Component({
selector: 'combo-billing-entity',
templateUrl: './combo-billing-entity.component.html'
})
export class ComboBillingEntityComponent extends CommonFieldFormComponent implements OnInit {
private selectUndefinedOptionValue:any;
billingEntities:BillingEntitity[] = [];
@Input()
private formGroup:FormGroup;
constructor(private billingService: BillingService, private formBuilder:FormBuilder)
{
super();
this.isRequired=true;
this.title="Billing Entity";
this.someExplanation="Identifies entity responsible for billing invoice";
this.formGroup = this.formBuilder.group({
billingEntity :['', Validators.required]
});
}
但毕竟我有这个错误:
ComboBillingEntityComponent.html:5错误错误:找不到具有未指定名称属性的控件 at _throwError(forms.es5.js:1852) at setUpControl(forms.es5.js:1760) 在FormGroupDirective.webpackJsonp ... / .. / .. / forms/@angular/forms.es5.js.FormGroupDirective.addControl(forms.es5.js:4733) 在FormControlName.webpackJsonp ... / .. / .. / forms/@angular/forms.es5.js.FormControlName._setUpControl(forms.es5.js:5321) 在FormControlName.webpackJsonp ... / .. / .. / forms/@angular/forms.es5.js.FormControlName.ngOnChanges(forms.es5.js:5239) at checkAndUpdateDirectiveInline(core.es5.js:10831) at checkAndUpdateNodeInline(core.es5.js:12330) at checkAndUpdateNode(core.es5.js:12269) 在debugCheckAndUpdateNode(core.es5.js:13130) 在debugCheckDirectivesFn(core.es5.js:13071)
任何想法如何将输入绑定到主要表单..我做错了什么?
答案 0 :(得分:0)
您的组件必须实现ControlValueAccessor
并注册它是一个多依赖项。 Pascal Precht在custom form controls in Angular上有一篇非常好的博文。
简而言之,在通过定义函数ControlValueAccessor
,writeValue
和registerOnChange
来实现registerOnTouched
之后,您必须提供现有值,以便Angular可以知道你正试图将它用作表单控件。
@Component({
// ...
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ComboBillingEntityComponent),
multi: true,
}
],
// ...
})
class ComboBillingEntityComponent implements ControlValueAccessor {
// ...
}
在此之后,您可以在模板中的formControlName
标记上使用<combo-billing-entity>
:
<combo-billing-entity formControlName="billingInfo"></combo-billing-entity>
答案 1 :(得分:0)
您的表单中有很多问题。您正尝试在输入字段中使用双向绑定,例如[(formGroup)]="partnerForm"
但是您无法使用@Output
实际触发双向绑定,因此您没有正确使用它
表单对象确实是一个对象,对象在JS中是可变的并通过引用传递。有时这不是理想的行为,但在这种情况下,我们需要这样,我们有嵌套组件。所以,无论你在子组件中形成字段,父母都会知道,所以你实际上并不需要双向绑定。
其次,请避免在被动形式中使用[(ngModel)]
。我注意到可能会发生奇怪的行为,这是可以理解的,因为我们有两个绑定到ngModel变量,另一个是表单控制变量。改为使用表单控件,并从模板中删除所有ngModel。您可以将值设置为表单控件,它基本上可以作为双向绑定使用,因为您可以随时从TS访问表单控件值。所以[(ngModel)]
在父级中构建整个表单,然后将表单组传递给子级,或者将嵌套的表单组传递给您的孩子。因此,在您的父级中,您实际上想要构建表单:
this.partnerForm = this.fb.group({
billingEntity: ['hey I am initial value']
})
您可以将初始值设置为billingEntity
,或者如果您需要在某个其他位置手动设置默认值,您可以通过以下方式执行此操作:this.partnerForm.get('billingEntity').setValue(...)
我们现在将此表单传递给孩子:
<combo-billing-entity [partnerForm]="partnerForm"></combo-billing-entity>
在孩子中我们将其注册为Input
:
@Input() formGroup: FormGroup;
然后我们可以使用它,例如:
<div [formGroup]="partnerForm">
<input formControlName="billingEntity" />
</div>
我看到你正在尝试使用[(ngModel)]
,但如上所述,你可以删除它并使用表单控件。该值很好地存储在formGroup.get('billingEntity').value
中,如前所述,如果需要在某个时刻设置值,则可以这样做。但是所有表单值都很好地存储在表单对象中,即partnerForm.value
。
这是一个简单的演示:http://plnkr.co/edit/AuidEMaaURsBPfDP8k0Q?p=preview
我建议你阅读有关嵌套表单的内容,这个非常适合开始使用:Nested Model-driven Forms