Angular2 Nested formGroups - formArrays and templa

2019-02-15 18:24发布

Here is the problem:

I have a complex form with nested formgroups, here is a "simplified" structure of what it looks like :

-> MyForm (formGroup)
    -> Whatever01 (formControl - input)
    -> Whatever02 (formControl - input)
    -> WhateverGroup01 (formGroup)
        -> Whatever03 (formControl - input)
        -> Whatever04 (formControl - input)
    -> WhateverArray01 (formArray)
        -> WhateverGroup02 (formGroup)
            -> Whatever05 (formControl - input)
            -> WhateverGroup03 (formGroup)
                -> Whatever06 (formControl - input)
        -> WhateverGroup04 (formGroup)
            -> Whatever07 (formControl - input)
    -> ...

Angular side, it should look somehow like this (not correct/complete, but just to give an idea) :

this.myForm = this.fb.group({
    whatever01: ['',Validators.compose([...])],
    whatever02: ['',Validators.compose([...])],
    whateverGroup01: this._formBuilder.group({
        whatever03: ['',Validators.compose([...])],
        whatever04: ['',Validators.compose([...])]
    }),
    whateverArray01: this._formBuilder.array([
        this._formBuilder.group({
            whatever05: ['',Validators.compose([...])],
            whateverGroup03: this._formBuilder.group({
                whatever06: ['',Validators.compose([...])]
            })
        }),
        this._formBuilder.group({
            whatever07: ['',Validators.compose([...])],
        })
    ])
    ...
});

Things go pretty fine from root myForm item to fetching the formArray, but then come the troubles....

So, I just can't access "whatever05" (and 06 but 05 does NOT work... so...) formControl to bind it to the template ! Here is what the template actually looks like (intentionnaly skipped the part before the array), the interesting part is the [????]="????", this is the problem actually.

<form [formGroup]="myForm" ...>
    <!-- ...skipped... -->
    <div formArrayName="whateverArray01" *ngFor="let item of myForm.controls.whateverGroup01.controls.whateverArray01.controls;let idx = index;" [formGroupName]="idx">
        <div [????]="????">
            <input formControlName="whatever05" ... />
            <div [????]="????">
                <input formControlName="whatever06" ... />
            </div>
        </div>    
    </div>
</form>

The formGroups located in the formArray have all the same structure.

Basically, the problem is that I canNOT access the formControls within the formGroups...

I tried several solutions, I used [formGroupName] , formGroupName (without brackets), [formGroup], formControlName, ... But cannot figure out what I have to use to be able to bind the corresponding formGroup/formControl with the data !

I come to this kind of errors by now :

formGroup expects a FormGroup instance. Please pass one in. 
// This when using [formGroup]="item.whateverGroup02"

Cannot find control with name: 'whatever05'
// When using [formGroup]="item.controls.whateverGroup02"

Cannot find control with path: 'whateverArray01 -> 0 ->'
// This when using [formGroupName]="whateverGroup02"

Thanks for reading / help

Here is a plunker with some code :

http://plnkr.co/edit/wf7fcHMkhIwzmLWLnCF8?p=preview

2条回答
男人必须洒脱
2楼-- · 2019-02-15 18:49

The build of your form seems correct to me. You have some trouble in your template, the iteration of your FormArray is incorrect, your FormArray is not inside the FormGroup WhateverGroup01, so the iteration should look like this:

*ngFor="let ctrl of myForm.controls.whateverArray01.controls;

As to the template part of your FormArray, it should look like this:

<div *ngFor="let ctrl of myForm.controls.whateverArray01.controls; let i = index" [formGroupName]="i">
   <input formControlName="whatever05" />
   <div formGroupName="whateverGroup03">
      <input formControlName="whatever06" />
   </div>
</div>

That should solve the issue :)

Here's a

Demo

查看更多
Summer. ? 凉城
3楼-- · 2019-02-15 18:52

First of all your view has wrong binding:

[formGroupName]="whateverGroup02"

There is no whateverGroup02 property in your component. We should pass string as follows:

formGroupName="whateverGroup02"

Then if you build group like:

this.fb.group({
  x: 1,
  y: {
    z: 2
  }
})

you will get

FormGroup
  -> FormControl with name `x` and value `1`   
  -> FormControl with name `y` and value `{ z: 2 }`

It means if you want to manipulate nested formGroups you have to create their. i.e.

let fGroups = data.map(rs => this.buildFormGroup(rs));
...
buildFormGroup(obj) {
  let formGroup: { [id: string]: AbstractControl; } = {};
  Object.keys(obj).forEach(key => {
    formGroup[key] = typeof obj[key] === 'object' ?
      this.buildFormGroup(obj[key]) : 
      new FormControl(obj[key]);
  });
  return this._formBuilder.group(formGroup);
}

Plunker Example

查看更多
登录 后发表回答