创建可重用的 FormGroup [英] Create a reusable FormGroup
问题描述
我知道创建自定义控件作为组件,但我不知道如何创建自定义组.
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).
Parent 有以下使用 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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!