Angular 强类型反应形式
Angular strongly typed reactive forms
我希望重构我的 Angular 项目中的大量组件,以具有强类型的 FormGroups、FormArrays 和 FormControls。
我只是在寻找一种实现强类型响应式表单的好方法。谁能根据自己的经验提供suggestions/recommendations?
谢谢。
编辑:
澄清一下,我所说的强类型是指目前当我创建 FormGroup 或 FormArray 时,我无法指定其中实际表单的结构。当我将此表单传递到我的应用程序中的各个组件时,我觉得我让维护变得更加困难。
最优雅的解决方案是利用 TypeScript 声明文件 (*.d.ts
) 引入扩展标准形式 类 的通用接口,如 AbstractControl
、FormControl
等。它不引入任何新功能并且在编译后没有占用空间 JavaScript,但同时执行强类型检查。
现在 suggested by Daniele Morosinotto in March this year and there are talks 将其包含在 Angular 9.
采用解决方案很简单:
- 从this gist下载
TypedForms.d.ts
并在你的项目中保存为src/typings.d.ts
(Angular 6+已经知道如何使用这个文件)。
- 只要您需要强类型验证(请参阅 that gist or stackblitz 中的示例),就开始使用新类型(
FormGroupTyped<T>
、FormControlTyped<T>
等)。
有关详细信息,请查看 blog post 分析强类型表单的可用解决方案。
我最终使用的解决方案是 library I found called ngx-strongly-typed-forms
它使您能够拥有强类型的 FormControls、FormGroups 和 FormArrays。有一些限制,但它确实对我的项目有很大帮助。
查看文档
我遇到了类似的问题,这是我的解决方案。我真的只关心表单的 'value' 类型,而不关心表单本身。它最终看起来像这样。
export interface UserFormValue {
first_name: string
last_name: string
referral: string
email: string
password: string
}
...
ngOnInit() {
this.userForm = this.fb.group({
first_name: [ '', Validators.required ],
last_name: [ '', Validators.required ],
referral: [ '' ],
email: [ '', [ Validators.required, Validators.email ] ],
password: [ '', [ Validators.required, Validators.minLength(8) ] ],
});
}
...
然后在模板中提交值
<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)">
...
</form>
现在您可以向提交功能添加类型
onSubmit(userForm: UserFormValue) {
...
}
它并不完美,但对于我的用例来说已经足够好了。我真希望有这样的。
userForm: FormGroup<UserFormValue>
对于那些想要其他解决方案的人。我发现 this article 正在谈论 angular 形式的强类型。以下是我的总结。
interface Person {
name: string;
email: string
}
// Controls in a form group that would emit a Person as it's value
type PersonControls = { [key in keyof Person]: AbstractControl };
type PersonFormGroup = FormGroup & { value: Person, controls: PersonControls };
export class MyFormComponent {
form = new FormGroup({
name: new FormControl(),
email: new FormControl()
} as PersonControls) as PersonFormGroup;
init() {
const name = this.form.controls.name; // strong typed!
}
}
如果您有嵌套类型的组,那么您可以这样做:
**models.ts
export type TCreateUserFields = {
first_name: string,
last_name: string,
accept_terms: boolean,
};
export type TPasswordsControls = {
passwords: FormGroup & {
password: AbstractControl,
confirm_password: AbstractControl
}
}
export type TPasswordsFields = {
passwords: {
password: string,
confirm_password: string
}
}
export type TAllFields = TCreateUserFields & TPasswordsFields;
export type TAllControls = TCreateUserControls & TPasswordsControls;
export type TCreateUserControls = {
[key in keyof TCreateUserFields]: AbstractControl
};
export type TCreateUserFormGroup = FormGroup & {value: TAllFields, controls: TAllControls};
**component.ts
this.registerationForm = this.fb.group(
{
first_name: new FormControl("", [Validators.required]),
last_name: new FormControl("", [Validators.required]),
accept_terms: new FormControl(false, [Validators.required]),
passwords: new FormGroup(
{
password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
confirm_password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
}, {
validators: <ValidatorFn>pwdConfirming({key:'password', confirmationKey:'confirm_password'})
}
)
} as TCreateUserControls) as TCreateUserFormGroup;
自 Angular 14 日(目前在 next
频道)开始提供严格类型的表格!
FormGroup
和 FormArray
classes 接受泛型,这是内部控件的类型。 FormControl
class 接受其值类型的泛型。还有一个名为 FormRecord
的新 class,用于动态控件组。
这是一个例子:
const party = new FormGroup({
address: new FormGroup({
house: new FormControl(123, {initialValueIsDefault: true}),
street: new FormControl('Powell St', {initialValueIsDefault: true}),
}),
formal: new FormControl(true),
foodOptions: new FormArray([
new FormControl('Soup'),
])
});
// whichHouse has type `number`
const whichHouse = party.get('address.house')!.value;
// Error: control "music" does not exist
const band = party.controls.music;
我希望重构我的 Angular 项目中的大量组件,以具有强类型的 FormGroups、FormArrays 和 FormControls。
我只是在寻找一种实现强类型响应式表单的好方法。谁能根据自己的经验提供suggestions/recommendations?
谢谢。
编辑:
澄清一下,我所说的强类型是指目前当我创建 FormGroup 或 FormArray 时,我无法指定其中实际表单的结构。当我将此表单传递到我的应用程序中的各个组件时,我觉得我让维护变得更加困难。
最优雅的解决方案是利用 TypeScript 声明文件 (*.d.ts
) 引入扩展标准形式 类 的通用接口,如 AbstractControl
、FormControl
等。它不引入任何新功能并且在编译后没有占用空间 JavaScript,但同时执行强类型检查。
现在 suggested by Daniele Morosinotto in March this year and there are talks 将其包含在 Angular 9.
采用解决方案很简单:
- 从this gist下载
TypedForms.d.ts
并在你的项目中保存为src/typings.d.ts
(Angular 6+已经知道如何使用这个文件)。 - 只要您需要强类型验证(请参阅 that gist or stackblitz 中的示例),就开始使用新类型(
FormGroupTyped<T>
、FormControlTyped<T>
等)。
有关详细信息,请查看 blog post 分析强类型表单的可用解决方案。
我最终使用的解决方案是 library I found called ngx-strongly-typed-forms
它使您能够拥有强类型的 FormControls、FormGroups 和 FormArrays。有一些限制,但它确实对我的项目有很大帮助。
查看文档我遇到了类似的问题,这是我的解决方案。我真的只关心表单的 'value' 类型,而不关心表单本身。它最终看起来像这样。
export interface UserFormValue {
first_name: string
last_name: string
referral: string
email: string
password: string
}
...
ngOnInit() {
this.userForm = this.fb.group({
first_name: [ '', Validators.required ],
last_name: [ '', Validators.required ],
referral: [ '' ],
email: [ '', [ Validators.required, Validators.email ] ],
password: [ '', [ Validators.required, Validators.minLength(8) ] ],
});
}
...
然后在模板中提交值
<form [formGroup]="userForm" (ngSubmit)="onSubmit(userForm.value)">
...
</form>
现在您可以向提交功能添加类型
onSubmit(userForm: UserFormValue) {
...
}
它并不完美,但对于我的用例来说已经足够好了。我真希望有这样的。
userForm: FormGroup<UserFormValue>
对于那些想要其他解决方案的人。我发现 this article 正在谈论 angular 形式的强类型。以下是我的总结。
interface Person {
name: string;
email: string
}
// Controls in a form group that would emit a Person as it's value
type PersonControls = { [key in keyof Person]: AbstractControl };
type PersonFormGroup = FormGroup & { value: Person, controls: PersonControls };
export class MyFormComponent {
form = new FormGroup({
name: new FormControl(),
email: new FormControl()
} as PersonControls) as PersonFormGroup;
init() {
const name = this.form.controls.name; // strong typed!
}
}
如果您有嵌套类型的组,那么您可以这样做:
**models.ts
export type TCreateUserFields = {
first_name: string,
last_name: string,
accept_terms: boolean,
};
export type TPasswordsControls = {
passwords: FormGroup & {
password: AbstractControl,
confirm_password: AbstractControl
}
}
export type TPasswordsFields = {
passwords: {
password: string,
confirm_password: string
}
}
export type TAllFields = TCreateUserFields & TPasswordsFields;
export type TAllControls = TCreateUserControls & TPasswordsControls;
export type TCreateUserControls = {
[key in keyof TCreateUserFields]: AbstractControl
};
export type TCreateUserFormGroup = FormGroup & {value: TAllFields, controls: TAllControls};
**component.ts
this.registerationForm = this.fb.group(
{
first_name: new FormControl("", [Validators.required]),
last_name: new FormControl("", [Validators.required]),
accept_terms: new FormControl(false, [Validators.required]),
passwords: new FormGroup(
{
password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
confirm_password: new FormControl("", [Validators.required, Validators.pattern(/^[~`!@#$%^&*()_+=[\]\{}|;':",.\/<>?a-zA-Z0-9-]+$/)]),
}, {
validators: <ValidatorFn>pwdConfirming({key:'password', confirmationKey:'confirm_password'})
}
)
} as TCreateUserControls) as TCreateUserFormGroup;
自 Angular 14 日(目前在 next
频道)开始提供严格类型的表格!
FormGroup
和 FormArray
classes 接受泛型,这是内部控件的类型。 FormControl
class 接受其值类型的泛型。还有一个名为 FormRecord
的新 class,用于动态控件组。
这是一个例子:
const party = new FormGroup({
address: new FormGroup({
house: new FormControl(123, {initialValueIsDefault: true}),
street: new FormControl('Powell St', {initialValueIsDefault: true}),
}),
formal: new FormControl(true),
foodOptions: new FormArray([
new FormControl('Soup'),
])
});
// whichHouse has type `number`
const whichHouse = party.get('address.house')!.value;
// Error: control "music" does not exist
const band = party.controls.music;