html - Obțin eroare după actualizarea de la Angular 8 la 12 - „Proprietatea 'controls' nu există pe tipul 'AbstractControl'”


Aveam un cod complet funcțional în Angular 8. Am decis să fac upgrade de la 8 la Angular 12.

Am un formular reactiv dinamic. Formularul are format de întrebări și răspunsuri. În funcție de cine se conectează, întrebările se schimbă. Răspunsul este în format Da/Nu. În funcție de cine se conectează și ce opțiune de răspuns este aleasă, câmpul de text, lista derulantă și căsuța de selectare sau toate cele menționate apar.

Aici este codul meu pentru formular

Component.ts

constructor(
    private router: Router,
    private datePipe: DatePipe,
    private route: ActivatedRoute,
    private formBuilder: FormBuilder) {      
    this.dynamicForm = this.formBuilder.group({
        questions: new FormArray([])
    });
    this.CreateForm();
}

get f() { return this.dynamicForm.controls; }
get t() { return this.f.questions as FormArray; }


CreateForm() {
    if (this.formdetail.questionList) {
        // CREATE Questions
        if (racialQues !==  this.formdetail.questionList[i].quetext && this.formdetail.questionList[i].quetext !== auditQues) {
            this.t.push(this.formBuilder.group({
                quesIndex: [i + 1],
                ...
                controlName: [this.formdetail.questionList[i].selectedAns, [Validators.required]]
            }));
        } else if (this.formdetail.questionList[i].quetext === auditQues) {
            this.t.push(this.formBuilder.group({
                quesIndex: [i + 1],
                ......
                selectedValue: [this.formdetail.auditTrail.selectedValue, this.reasonValidator],
            }));
        } else if (this.formdetail.questionList[i].quetext === racialQues) {
      
            this.t.push(this.formBuilder.group({
                quesIndex: [i + 1],
                ......
                selectedAuxAns: [this.formdetail.questionList[i].val, [this.auxAnsValidator]]
            }));
        }
    }
}

Iată html-ul

<form [formGroup]="dynamicForm"> 
<!--  Question Start -->
<div *ngFor="let ticket of t.controls; let i = index">
    <div [formGroup]="ticket" class="form-row">  
        <div class="input-group col-md-12" style="padding: .15em .5em">                                        
            <div class="input-group-prepend col-md-10" style="padding: 0; margin: 0;">                
                <label class="input-group-text w-15">{{i + 1}}</label>
                <label class="input-group-text w-100" style="text-align: left; white-space: normal;">{{ticket.controls.name.value}}</label>
            </div>                                 
            <select formControlName="controlName" class="form-control col-md-2" style="height:auto !important;" 
                [ngClass]="{ 'is-invalid': submitted && ticket.controls.controlName.errors }"
                (change)="onChange($event.target.value, i)">
                <option [ngValue]="null"> --Select-- </option>
                <option *ngFor="let ansItem of formdetail.questionList[i].answerList" [ngValue]="ansItem" >{{ansItem.anstext}}</option>
            </select>
            <div *ngIf="submitted && ticket.controls.controlName.errors" class="invalid-feedback" style="height:auto !important;" 
            [ngClass]="{ 'input-group-append': submitted && ticket.controls.controlName.errors,
                         'col-md-1': submitted && ticket.controls.controlName.errors }">
                <div *ngIf="ticket.controls.controlName.errors.required">Required</div>
            </div>
            .
            .
            .
            .
            
        </div>  
    /div>
</div>     
<!--  Question End -->                
</form>    

Acum primesc eroare în „ticket.control”

Proprietatea 'controls' nu există pe tipul 'AbstractControl'.

Nu sunt sigur de ce primesc această eroare după upgrade. Am încercat ticket.['control'] sau ticket.get('controlName') așa cum a sugerat un alt articol despre o eroare similară pe StackOverflow, dar nimic nu funcționează

Iată captura de ecran a erorii

Orice ajutor va fi apreciat. Mulțumesc

Răspuns #1

al tău t este de tip FormArray, array-ul FormArray.controls este de tip AbstractControl[], astfel încât fiecare ticket la

<div *ngFor="let ticket of t.controls; let i = index">

linia este de tip AbstractControl, care nu are proprietatea controls, așa cum se vede în eroarea TS din captura ta de ecran. TS nu știe că fiecare ticket este de fapt de tip FormGroup (setat aici this.t.push(this.formBuilder.group({...}) și care are proprietatea controls).

Deci poți încerca să adaugi un alt getter tControls:

get f() { return this.dynamicForm.controls; }
get t() { return this.f.questions as FormArray; }
get tControls() { return this.t.controls as FormGroup[]; }

și folosește-l în cadrul *ngFor:

<div *ngFor="let ticket of tControls; let i = index">
    <div [formGroup]="ticket" class="form-row">
    ...

Vă rugăm să rețineți că acum [formGroup] va fi de asemenea completat corespunzător cu FormGroup și nu cu AbstarctControl

Probabil că una dintre actualizările tale Angular a adăugat

"angularCompilerOptions": {
  "fullTemplateTypeCheck": true,
  "strictInputTypes": true,
}

în fișierul tău tsconfig.json, îl poți verifica doar setând aceste valori la false și reconstruind aplicația ta, dar recomand să lași aceste verificări stricte.

Răspunsul #2

Aceasta este un răspuns generic (deci cod generic) pentru a ajuta la rezolvarea unei astfel de probleme. Să presupunem că ai un ciclu printr-un câmp (numiți-l elements) de tip FormArray. Acest câmp face parte dintr-un formular de tip FormGroup

În codul vostru logic ts (implementarea logicii) ar trebui să aveți ceva de genul:

  form = new FormGroup({
   //.. other fields
    elements: new FormArray([]),
  });

În șablonul tău (fișierul html), trebuie să parcurgi câmpul elements:

<li
  *ngFor="let element of elements.controls">
  {{ element.value }}
</li>

Pentru a-i spune Angular CLI că elements are o proprietate de tip controls (deci de tip FormArray), trebuie să o formatezi în codul tău logic ts astfel (implementează un getter pentru câmpul elements):

  get elements() {
    return this.form.get('elements') as FormArray;
  }