创建可重用的 FormGroup
Create a reusable FormGroup
我知道创建自定义 控件 作为组件,但我不知道如何创建自定义 组 。
同样我们可以通过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) 封装一组出现在多个表单中的字段,例如地址(一组国家、州、城市、地址、门牌号)或出生日期(年、月、日)。
示例用法(不是实际工作代码)
父级使用 FormBuilder
构建了以下表单:
// parent model
form = this.fb.group({
username: '',
fullName: '',
password: '',
address: this.fb.group({
country: '',
state: '',
city: '',
street: '',
building: '',
})
})
父模板(为简洁起见不可访问且非语义):
<!-- parent template -->
<form [groupName]="form">
<input formControlName="username">
<input formControlName="fullName">
<input formControlName="password">
<address-form-group formGroup="address"></address-form-group>
</form>
现在 AddressFormGroupComponent
知道如何处理内部具有这些特定控件的组。
<!-- child template -->
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">
Angular 表单没有组名称和表单控件名称的概念。但是,您可以通过将子模板包装在表单组中来轻松解决此问题。
这是一个类似于您发布的标记的示例 - https://plnkr.co/edit/2AZ3Cq9oWYzXeubij91I?p=preview
@Component({
selector: 'address-form-group',
template: `
<!-- child template -->
<ng-container [formGroup]="group.control.get(groupName)">
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">
</ng-container>
`
})
export class AddressFormGroupComponent {
@Input() public groupName: string;
constructor(@SkipSelf() public group: ControlContainer) { }
}
@Component({
selector: 'my-app',
template: `
<!-- parent template -->
<div [formGroup]="form">
<input formControlName="username">
<input formControlName="fullName">
<input formControlName="password">
<address-form-group groupName="address"></address-form-group>
</div>
{{form?.value | json}}
`
})
export class AppComponent {
public form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
username: '',
fullName: '',
password: '',
address: this.fb.group({
country: '',
state: '',
city: '',
street: '',
building: '',
})
});
}
}
, and that is injecting the ControlContainer
.
中提到了我遗漏的部分
事实证明,如果您将 formGroupName
放在组件上,并且如果该组件注入 ControlContainer
,您将获得对包含该表单的容器的引用。从这里开始很容易。
我们创建一个子表单组件。
@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 中删除,因此没有不必要的元素。
现在我们可以直接使用这个组件了。
@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) {}
}
你可以看到一个live demo on StackBlitz.
这比 rusev 的答案在几个方面有所改进:
- 没有自定义
groupName
输入;相反,我们使用 Angular 提供的 formGroupName
- 不需要
@SkipSelf
装饰器,因为我们 不是 注入父控件,而是我们需要的
- 不尴尬
group.control.get(groupName)
这是去父级为了抢自己
我知道创建自定义 控件 作为组件,但我不知道如何创建自定义 组 。
同样我们可以通过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) 封装一组出现在多个表单中的字段,例如地址(一组国家、州、城市、地址、门牌号)或出生日期(年、月、日)。
示例用法(不是实际工作代码)
父级使用 FormBuilder
构建了以下表单:
// parent model
form = this.fb.group({
username: '',
fullName: '',
password: '',
address: this.fb.group({
country: '',
state: '',
city: '',
street: '',
building: '',
})
})
父模板(为简洁起见不可访问且非语义):
<!-- parent template -->
<form [groupName]="form">
<input formControlName="username">
<input formControlName="fullName">
<input formControlName="password">
<address-form-group formGroup="address"></address-form-group>
</form>
现在 AddressFormGroupComponent
知道如何处理内部具有这些特定控件的组。
<!-- child template -->
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">
Angular 表单没有组名称和表单控件名称的概念。但是,您可以通过将子模板包装在表单组中来轻松解决此问题。
这是一个类似于您发布的标记的示例 - https://plnkr.co/edit/2AZ3Cq9oWYzXeubij91I?p=preview
@Component({
selector: 'address-form-group',
template: `
<!-- child template -->
<ng-container [formGroup]="group.control.get(groupName)">
<input formControlName="country">
<input formControlName="state">
<input formControlName="city">
<input formControlName="street">
<input formControlName="building">
</ng-container>
`
})
export class AddressFormGroupComponent {
@Input() public groupName: string;
constructor(@SkipSelf() public group: ControlContainer) { }
}
@Component({
selector: 'my-app',
template: `
<!-- parent template -->
<div [formGroup]="form">
<input formControlName="username">
<input formControlName="fullName">
<input formControlName="password">
<address-form-group groupName="address"></address-form-group>
</div>
{{form?.value | json}}
`
})
export class AppComponent {
public form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
username: '',
fullName: '',
password: '',
address: this.fb.group({
country: '',
state: '',
city: '',
street: '',
building: '',
})
});
}
}
ControlContainer
.
事实证明,如果您将 formGroupName
放在组件上,并且如果该组件注入 ControlContainer
,您将获得对包含该表单的容器的引用。从这里开始很容易。
我们创建一个子表单组件。
@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 中删除,因此没有不必要的元素。
现在我们可以直接使用这个组件了。
@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) {}
}
你可以看到一个live demo on StackBlitz.
这比 rusev 的答案在几个方面有所改进:
- 没有自定义
groupName
输入;相反,我们使用 Angular 提供的 - 不需要
@SkipSelf
装饰器,因为我们 不是 注入父控件,而是我们需要的 - 不尴尬
group.control.get(groupName)
这是去父级为了抢自己
formGroupName