【问题标题】:Angular strongly typed reactive formsAngular 强类型反应形式
【发布时间】:2019-07-29 21:51:24
【问题描述】:

我希望在我的 Angular 项目中重构大量组件,使其具有强类型的 FormGroups、FormArrays 和 FormControls。

我只是在寻找一种实现强类型响应式表单的好方法。任何人都可以根据自己的经验提供建议/建议吗?

谢谢。

编辑:

为了澄清,强类型是指目前当我创建 FormGroup 或 FormArray 时,我无法指定其中实际表单的结构。当我将此表单传递给我的应用程序中的各种组件时,我会觉得我让维护变得更加困难。

【问题讨论】:

  • 你的strongly-typed的意思在这里不是很清楚。您能否举个例子来详细说明您在寻找什么?
  • @SiddAmjera 澄清一下,强类型是指目前当我创建 FormGroup 或 FormArray 时,我无法指定其中实际表单的结构。当我将此表单传递给我的应用程序中的各个组件时,我会觉得我让维护变得更加困难。
  • 您是否可以创建一个示例 StackBlitz,尽可能少地复制您的场景?
  • @SiddAmjera 对不起,也许我解释得不够清楚。这不是一段特定的代码。但希望这可以解释问题:stackblitz.com/edit/angular-tlfrgt
  • Angular 团队目前正在研究它,他们拥有通用/类型化形式的 MVP! github.com/angular/angular/issues/13721#issuecomment-942910823

标签: angular typescript angular-reactive-forms reactive-forms


【解决方案1】:

最优雅的解决方案是利用 TypeScript 声明文件 (*.d.ts) 引入扩展标准表单类(如 AbstractControlFormControl 等)的通用接口。它不引入任何新功能,并且在编译后的 JavaScript,但同时强制执行强类型检查。

今年 3 月 Daniele Morosinotto 的 suggestedthere are talks 现在将其包含在 Angular 9 中。

采用该解决方案很简单:

  1. this gist 下载TypedForms.d.ts 并将其另存为src/typings.d.ts 在您的项目中(Angular 6+ 已经知道如何使用此文件)。
  2. 只要您需要强类型验证(参见that giststackblitz 中的示例),就开始使用新类型(FormGroupTyped<T>FormControlTyped<T> 等)。

有关更多信息,请查看blog post 分析强类型表单的可用解决方案。

【讨论】:

  • 从哪里导入FormGroupTyped
  • 没关系,我使用的是 Lib,您还必须将 TypedForms.d.ts 文件复制到每个库中......
【解决方案2】:

我最终使用的解决方案是library I found called ngx-strongly-typed-forms

它使您能够拥有强类型的 FormControls、FormGroups 和 FormArrays。有一些限制,但它肯定对我的项目有很大帮助。

您可以在https://github.com/no0x9d/ngx-strongly-typed-forms查看文档

【讨论】:

  • 我在一个多月前创建了一个问题,但似乎还没有得到任何回应。从外观上看,这个项目可能已经过时了,我不建议任何人使用它!
  • 缺少类型信息的(仍未解决的)角度问题是github.com/angular/angular/issues/13721。那里提到了一些更强大的替代方案(如@ng-stack/forms)。
【解决方案3】:

我遇到了类似的问题,这是我的解决方案。我真的只关心表单的“价值”类型,而不是表单本身。它最终看起来像这样。

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&lt;UserFormValue&gt;

【讨论】:

    【解决方案4】:

    对于那些想要另一种解决方案的人。我发现this article 谈论有角形式的强类型。以下是我的总结。

    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!
      }
    }
    

    【讨论】:

    • 我更喜欢这个。谢谢!
    【解决方案5】:

    如果您有嵌套类型的组,那么您可以这样做:
    **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};
    

    **组件.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;
    

    【讨论】:

      猜你喜欢
      • 2018-11-30
      • 1970-01-01
      • 1970-01-01
      • 2019-09-11
      • 2019-02-18
      • 1970-01-01
      • 1970-01-01
      • 2023-01-31
      • 2019-06-18
      相关资源
      最近更新 更多