【问题标题】:Angular: Deep copy a reactive formAngular:深度复制反应形式
【发布时间】:2019-08-07 06:14:00
【问题描述】:

我需要制作一个响应式表单的深层副本。 我曾尝试使用 ES6 扩展语法来克隆表单。我已经使用 Typescript 泛型将扩展语法的返回值类型转换为 FormGroup。此外,克隆表单变量的类型设置为FormGroup

但是当通过这种方式克隆表单时,克隆的表单变量上的类型丢失了,即不再是FormGroup的类型。所以,克隆出来的表格是不可用的。

这是相同的堆栈闪电战:form cloning

上述克隆方式出了什么问题?为什么FormGroup类型在克隆表单上丢失了?

【问题讨论】:

  • 您不能克隆类型。它们只是为了方便。 Javascript 没有类型(有点),打字稿有。
  • 您正在做的是创建一个 POJO(不是 FormGroup 的实例:这需要调用其构造函数)并将 FormGroup 的属性复制到 POJO。它根本不是深拷贝,而是浅拷贝,而且它不会创建 FormGroup 的实例。为什么要克隆 FormGroup?你想解决什么具体问题?
  • 这只是解决您要解决的任何问题的错误方法。通常,您需要一组有限的表单,只需创建一个方法来创建您需要的表单,以便您可以根据需要实例化它们。
  • 在使用扩展语法后,使用 TypeScript 泛型将结果类型转换为 FormGroup 有什么问题吗?这根本就不是类型转换吗?
  • 这能回答你的问题吗? Deep copy of Angular Reactive Form?

标签: angular angular-reactive-forms deep-copy


【解决方案1】:

只需使用返回 FormGroup 的函数。您可以使用 setValue 或 patchValue 来提供相同的值。有些喜欢(我直接使用 FormGroup 的构造函数,但你也可以使用 FormBuilder)

  createForm(data:any)
  {
    data=data || {name:null,group:{prop1:null,prop2:null}}
    return new FormGroup({
      name: new FormControl(data.name),
      group:new FormGroup({
        prop1:new FormControl(data.group.prop1),
        prop2:new FormControl(data.group.prop2)
      })
    })
  }

/*you can also
  createForm(data:any)
  {
    const form=new FormGroup({
      name: new FormControl(),
      group:new FormGroup({
        prop1:new FormControl(),
        prop2:new FormControl()
      })
    })
    if (data)
      form.patchValue(data)

    return form
  }
  */

在 ngOnInit 中,例如

  ngOnInit() {
       this.myForm=this.createForm({name:"name",group:{prop1:"prop1",prop2:"prop2"}});
       this.myForm2=this.createForm(null);
       this.myForm2.patchValue(this.myForm.value)
       //or this.myForm2.setValue(this.myForm.value)
  }

link

【讨论】:

  • 这种方法的缺点是任何已经存在且与默认值不同的控制状态(禁用、脏等)都将丢失。
【解决方案2】:

Lodash 在深度克隆 FormGroups 时效果很好,即使它们是嵌套的。如果您正在处理动态表单,手动重新创建表单可能会导致大量代码行(例如检查条件表单/控件的存在)。鉴于这种情况,在大多数情况下,我们可以通过导入 * as _ from 'lodash' 并使用 .cloneDeep. 克隆 FormGroup、FormArray 或 FormControl 来解决它,例如:

const clonedForm = _.cloneDeep(this.myForm);

然后您将能够像使用myForm 一样使用clonedForm 及其内部控件,而无需修改myForm 的嵌套控件。

【讨论】:

    【解决方案3】:

    这是我的解决方案:

    app.component.ts

    export class AppComponent {
      formulario = new Formulario();
    }
    
    export class Formulario {
      getFormulario() {
        return {
          nombre: new FormControl('', [Validators.required]),
          email: new FormControl('', [Validators.required, Validators.email]),
          password: new FormControl(''),
          cod_perfil: new FormControl('', [Validators.required]),
          validoHasta: new FormControl('')
        };
      }
    }
    

    app.component.html

    <child [formularios]="formulario"></child>
    

    现在在这里和任何地方您都可以获得表单的不同实例,

    child.component.ts

    export class ChildComponent implements OnInit {
      @Input() formularios: any;
      @Output() formulariosIdiomas = new EventEmitter<any>();
      langs = ['es', 'en'];    
    
      ngOnInit() {
        console.log(this.formularios.getFormulario());
    
        // Different instances
        this.langs.forEach(lang => {
          this.formulariosIdiomas[lang] = new FormGroup(
            this.formularios.getFormulario()
          );
        });
    
      }
    }
    

    【讨论】:

    • 这行不通,首先。 this.formulariosIdiomas[lang] 指的是EventEmitter。 EventEmitter 不是 FormGroups 的集合
    【解决方案4】:

    您可以使用Objectassign() 方法,语法如下:

    Object.assign(target, ...sources)
    

    在你的情况下,你可以这样做:

    this.myForm2 = Object.assign({}, this.myForm)
    

    那么,Object.assign() 做了什么?

    此方法用于复制所有可枚举自己的值 从一个或多个源对象到目标对象的属性。它会 返回目标对象。

    详情请前往here

    希望这会有所帮助。

    【讨论】:

    • 此解决方案不起作用,因为它不会复制与 AbstractControl 相关的方法,例如 getsetValidators...
    猜你喜欢
    • 2018-11-30
    • 2019-09-11
    • 2019-02-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 2016-07-07
    • 2017-07-21
    相关资源
    最近更新 更多