typescript - Angular 10 FormArray FEL Fel: Kan inte hitta kontroll med namn: '[object Object],[object Object],[object Object]'


Jag försöker skapa ett formulär som visar dynamiska kryssrutor, där minst en ska vara markerad för att kunna gå vidare. Jag behöver också få en lista med markerade kryssrutor.

Här är koden från komponenten:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { FormControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.scss']
})
export class ProductsComponent implements OnInit {
  productsForm: FormGroup;
  items = [
    {key: 'key1', text: 'text1'},
    {key: 'key2', text: 'text2'},
    {key: 'key3', text: 'text3'},
  ];
  checkboxGroup = new FormArray(this.items.map(item => new FormGroup({
    id: new FormControl(item.key),
    text: new FormControl(item.text),
    checkbox: new FormControl(false)
  })));

  constructor(private router: Router, private fb: FormBuilder) { }

  
  ngOnInit() {

    let hiddenControl = new FormControl(this.mapItems(this.checkboxGroup.value), Validators.required);

    this.checkboxGroup.valueChanges.subscribe((v) => {
      console.log(v);
      hiddenControl.setValue(this.mapItems(v));
    });

    this.productsForm = new FormGroup({
      items: this.checkboxGroup,
      selectedItems: hiddenControl
    });
    console.log(this.checkboxGroup.controls);
  }

  mapItems(items) {
    let selectedItems = items.filter((item) => item.checkbox).map((item) => item.id);
    return selectedItems.length ? selectedItems : null;
  }

  onSubmit() {
    this.router.navigate(['/result'], { skipLocationChange: true });
  }
}

HTML:

<h3>Select products</h3>
<form [formGroup]="productsForm">
    <div [formArrayName]="items" [class.invalid]="!productsForm.controls.selectedItems.valid">
      <div *ngFor="let control of checkboxGroup.controls; let i = index;" [formGroup]="control">
        <div>
            <input type="checkbox" formControlName="checkbox" id="{{ control.controls.id.value }}">
            <label attr.for="{{ control.controls.id.value }}">{{ control.controls.text.value }}</label>
        </div>
      </div>
    </div>
    <div [class.invalid]="!productsForm.controls.selectedItems.valid" *ngIf="!productsForm.controls.selectedItems.valid">
      Check at least one checkbox!
    </div>
    <hr>
    <pre>{{productsForm.controls.selectedItems.value | json}}</pre>
</form>

I HTML försökte jag tidigare iterera genom FormArray-instansen med hjälp av FormGroup-instansen på detta sätt: productsForm.controls.items.controls. Men det brukade ge ett fel under kompileringen som lyder så här:

Egenskapen 'controls' finns inte på typen 'AbstractControl'.

Nu har jag blivit av med det felet och projektet kompilerar, men nu returnerar det

FEL Fel: Kan inte hitta kontroll med namn: '[object Object],[object Object],[object Object]

vilket inte är till någon hjälp alls.

Om jag console.log checkboxGroup.controls returnerar det mina kryssrutor på det sätt jag vill.

Jag använder Angular 10.

Snälla hjälp!

Svar #1

Kan inte kalla det ett bra svar, per se, så jag är fortfarande öppen för bättre svar, men detta tvingar koden att fungera.

Jag återvände till att iterera med productsForm.controls.items.controls, men jag skapade också en getter som ser ut så här:

 get checkboxControls() {
    // assign type 'any' to this.productsForm.controls.items which previously was 'AbstractControls'
    let checkbox = this.productsForm.controls.items as any
    // now you can magically call the 'controls' property and iterate, congratulations
    return checkbox.controls
  }

I HTML på rad 4 byt ut checkboxGroup.controls mot vår nya checkboxControls getter:

<div *ngFor="let control of checkboxControls; let i = index;" [formGroup]="control">
        <div>
            <input type="checkbox" formControlName="checkbox" id="{{ control.controls.id.value }}">
            <label attr.for="{{ control.controls.id.value }}">{{ control.controls.text.value }}</label>
        </div>
</div>

Här är en demolänk om någon vill testa det. Fungerar för både Angular 9 och 10. Lycka till!