【问题标题】:Nested form components are not set with initial values on submit嵌套表单组件未在提交时设置初始值
【发布时间】:2019-10-28 17:38:16
【问题描述】:

我正在尝试使用 ControlValueAccessors 以反应形式以角度实现嵌套表单组件,并且我一直在遵循本指南:https://blog.angularindepth.com/angular-nested-reactive-forms-using-cvas-b394ba2e5d0d

除了一个主要问题外,我已经完成了所有工作。如果我的表单是预先填充的,即表单用于编辑现有数据而不是创建,那么如果相应的子组件表单值没有更改,则在提交时不会在表单的值上设置初始数据。

我在以下链接上有一个示例设置(打开右下角的控制台): https://stackblitz.com/edit/angular-nested-forms-cva-izbrht

如您所见,如果您立即按下提交,表单值包含两个属性,其值只是两个空字符串。如果您编辑例如输入名字然后提交,你会看到 basicInfo 属性现在已经正确设置了它的值。

【问题讨论】:

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


【解决方案1】:

我通过在父组件中创建完整的 FormGroup 来解决它,然后将子表单作为输入传递给子组件。这消除了使用 ControlValueAccessors 的需要。

我对这个解决方案不满意,因为我希望子组件负责创建他们的表单组,但我找不到任何解决我的问题的方法,所以现在必须这样做。

【讨论】:

  • 对我来说,孩子创建表单是没有意义的,但是您始终可以在创建表单组的子组件中创建一个函数,并在您的主组件中使用 ViewChild 调用此函数@ 987654321@
  • 有趣的想法,可行。但是,如果您建议父母创建完整的表格,也许我应该采用上述解决方案?
  • 看我的另一个答案。对我来说,没有必要创建一个自定义表单控件来拥有一个表单组。对我来说,自定义表单控件是“特殊控件”,例如可以,例如一个数据选择器、一个日历、一个日期选择器范围、一个返回选项数组的复选框列表 select、一个 groupbuttons ......这只是一个非常个人的意见 enad,当然有些情况下一个想法或另一个是英勇的。例如如果我们想控制一张信用卡(输入卡号和 CVC 和 caducity 日期),创建一个自定义 formControl 还是只创建一个组件?对我来说,这两个选项都有效
【解决方案2】:

@langen,对我来说是使用 [formGroup] 和 [formControl] 。这是question in stackoverflowstackblitz 的评论

我的主要

<form [formGroup]="formGroup">
  <app-personal-details-form [formGroup]="formGroup"></app-personal-details-form>
</form>
//It's in main where I create the formGroup:
formGroup = new FormGroup(
    {
      name: new FormGroup({
        firstname: new FormControl(null, { validators: [Validators.required] }),
        lastname: new FormControl(null, { validators: [Validators.required] }),
      }),
      gender: new FormControl(null, { validators: [Validators.required] }),
      address: new FormGroup({
        streetaddress: new FormControl(null, { validators: [Validators.required] }),
        city: new FormControl(null, { validators: [Validators.required] }),
        state: new FormControl(null, { validators: [Validators.required] }),
        zip: new FormControl(null, { validators: [Validators.required] }),
        country: new FormControl(null, { validators: [Validators.required] })
      }),
      phone: new FormGroup({
        phone: new FormControl(null, { validators: [Validators.required] }),
        countrycode: new FormControl(null, { validators: [Validators.required] }),
      })

    })

组件的其余部分:

个人资料

<div [formGroup]="formGroup">
    <app-name-form [formGroup]="formGroup.get('name')"></app-name-form>
    <select formControlName="gender">
    <option *ngFor="let gender of Gender | keyvalue" [value]="gender.value">{{ gender.value }}</option>
  </select>
  <app-address-form [formGroup]="formGroup.get('address')"></app-address-form>
  <app-phone-form [formGroup]="formGroup.get('phone')"></app-phone-form>
</div>
//and 
@Input() formGroup:FormGroup;

地址形式

<div [formGroup]="formGroup">
  <input type="text" placeholder="Street address" formControlName="streetaddress">
  <span *ngIf="formGroup.get('streetaddress').invalid">*</span>
  <input type="text" placeholder="City" formControlName="city">
  <input type="text" placeholder="State" formControlName="state">
  <input type="text" placeholder="Zip" formControlName="zip">
  <input type="text" placeholder="Country" formControlName="country">
</div>
//and 
@Input() formGroup;

名称形式

<div [formGroup]="formGroup">
  <input type="text" placeholder="First name" formControlName="firstname">
  <input type="text" placeholder="Last name" formControlName="lastname">
</div>
//and
    @Input() formGroup;

等等

【讨论】:

    【解决方案3】:

    这是我的解决方案,

    将 registerOnChange 更改为:

    registerOnChange(fn) {
      this.onChange = fn;
    }
    

    然后像这样在您的子组件 ngOnInit 钩子中调用 onChange 方法:

     setTimeout(() => {
      this.onChange(this.form.value);
    });
    

    完成!注意使用 setTimeout 换行,否则不起作用。

    【讨论】:

      【解决方案4】:

      @Lagen,当您有一个自定义表单控件时,您需要在组件中提供提要。例如在您的 billing-info.component 中。

      public nestedForm: FormGroup = new FormGroup({
        basicInfo: new FormControl({fname:"Carl init",email:"myemail init@whatever.com"}),
        address: new FormControl({addressLine:"My address",areacode:'12345 new'})
        });
      

      当然,您可以删除组件中的初始化值。

      是的,FormControl 可以存储一个对象。您可以将 customForm 控件视为“黑匣子”。有趣的是你提供的价值和你得到的价值——而不是它是如何制作的——(我个人认为使用自定义表单控件创建嵌套表单是用大锤敲碎坚果)

      【讨论】:

        【解决方案5】:

        创建父表单本身时,可以将默认值传递给嵌套表单。这将解决问题the form is used to edit existing data instead of creating, then the initial data is not set on the form's value upon submit if the corresponding child component form values hasn't been changed.

        this.nestedForm= new FormGroup({
          basicInfo: defaultValues ? new FormControl(defaultValues.basicInfo) : new FormControl(),
          address: defaultValues ? new FormControl(defaultValues.address) : new FormControl()
        });
        

        所以这里是defaultValues 对象来设置默认值,例如https://blog.angularindepth.com/angular-nested-reactive-forms-using-cvas-b394ba2e5d0d

        const defaultValues = {
          basicInfo: {
            fname: 'suchin',
            lname: 'b'
          },
          address: {
            addressLine: 'Home',
            areacode: 'Test Code'
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2014-11-07
          • 1970-01-01
          • 2020-11-07
          • 2018-07-29
          • 2021-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多