问题描述
我知道创建自定义控件作为组件,但是我不知道如何创建自定义组.
I am aware of creating custom controls as components, but I can't figure out how to create custom groups.
我们可以通过实现ControlValueAccessor
并使用诸如<my-cmp formControlName="foo"></my-cmp>
,如何为一个组 达到这种效果?
The same we can do this by implementing ControlValueAccessor
and using a custom component like <my-cmp formControlName="foo"></my-cmp>
, how can we achieve this effect for a group?
<my-cmp formGroupName="aGroup"></my-cmp>
两个非常常见的用例是(a)将长格式分成多个步骤,每个步骤都放在一个单独的组件中;(b)封装一组以多种形式出现的字段,例如地址(国家/地区,州,城市,地址,门牌号)或出生日期(年,月,日).
Two very common use-cases would be (a) separting a long form into steps, each step in a separate component and (b) encapsulating a group of fields which appear across multiple forms, such as address (group of country, state, city, address, building number) or date of birth (year, month, date).
父母的以下表单是使用 FormBuilder
构建的:
Parent has the following form built with FormBuilder
:
// parent model
form = this.fb.group({
username: '',
fullName: '',
password: '',
address: this.fb.group({
country: '',
state: '',
city: '',
street: '',
building: '',
})
})
父模板(为简洁起见,它是不可访问的和非语义的):
Parent template (inaccessible and non-semantic for brevity):
<!-- parent template -->
<form [groupName]="form">
<input formControlName="username">
<input formControlName="fullName">
<input formControlName="password">
<address-form-group formGroup="address"></address-form-group>
</form>
现在,此AddressFormGroupComponent
知道如何处理内部具有这些特定控件的组.
Now this AddressFormGroupComponent
knows how to handle a group which has these specific controls inside of it.
<!-- child template -->
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">
推荐答案
rusev的答案,这就是注入 ControlContainer
.
结果表明,如果将formGroupName
放置在组件上,并且该组件注入ControlContainer
,则会获得对包含该表单的容器的引用.从这里很容易.
Turns out that if you place formGroupName
on a component, and if that component injects ControlContainer
, you get a reference to the container which contains that form. It's easy from here.
我们创建一个子表单组件.
We create a sub-form component.
@Component({
selector: 'sub-form',
template: `
<ng-container [formGroup]="controlContainer.control">
<input type=text formControlName=foo>
<input type=text formControlName=bar>
</ng-container>
`,
})
export class SubFormComponent {
constructor(public controlContainer: ControlContainer) {
}
}
请注意我们如何需要输入包装.我们不需要表单,因为它已经在表单中了.因此,我们使用ng-container
.这将与最终DOM分离,因此没有不必要的元素.
Notice how we need a wrapper for the inputs. We don't want a form because this will already be inside a form. So we use an ng-container
. This will be striped away from the final DOM so there's no unnecessary element.
现在我们可以使用此组件.
Now we can just use this component.
@Component({
selector: 'my-app',
template: `
<form [formGroup]=form>
<sub-form formGroupName=group></sub-form>
<input type=text formControlName=baz>
</form>
`,
})
export class AppComponent {
form = this.fb.group({
group: this.fb.group({
foo: 'foo',
bar: 'bar',
}),
baz: 'baz',
})
constructor(private fb: FormBuilder) {}
}
您可以看到实时演示 >在StackBlitz上.
You can see a live demo on StackBlitz.
这是在某些方面对rusev的回答的改进:
This is an improvement over rusev's answer in a few aspects:
- 无自定义
groupName
输入;相反,我们使用Angular提供的formGroupName
- 不需要
@SkipSelf
装饰器,因为我们不是 注入父控件,而是我们需要的 - 没有尴尬的
group.control.get(groupName)
会为了获取自己而交给父母.
- no custom
groupName
input; instead we use theformGroupName
provided by Angular - no need for
@SkipSelf
decorator, since we're not injecting the parent control, but the one we need - no awkward
group.control.get(groupName)
which is going to the parent in order to grab itself.
这篇关于创建一个可重用的FormGroup的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!