DotNetBeginner
DotNetBeginner

Reputation: 439

Getting error after upgrading from Angular 8 to 12 - "Property 'controls' does not exist on type 'AbstractControl' "

I had a fully functioning code in Angular 8. I decided to upgrade from 8 to Angular 12.

I have a dynamic reactive form. The form is of question answer format. Based on who is login in the questions change. The answer is of Yes/No format. Based on who is login in and what answer option is chosen textbox dropdown and checkbox or all the there mentioned appreas.

Here is my code for the form

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]]
            }));
        }
    }
}

Here is the html

<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>    

Now I am getting error in "ticket.control"

Property 'controls' does not exist on type 'AbstractControl'.

I am not sure why I am getting this error after upgrade. I have tried ticket.['control'] or ticket.get('controlName') as suggested by other article of similar error in stackoverflow but nothing works

Here is the snapshot of error

enter image description here

Any help will be appreciated. Thanks

Upvotes: 2

Views: 768

Answers (3)

Youssef
Youssef

Reputation: 3114

This is a generic answer (so generic code) to help fixing such an issue. Let's suppose you have a loop through a field (call it elements) of type FormArray. This field is part of a form of type FormGroup

In your ts logic code (logic implementation) you should have something like:

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

In your template (html file), you need to toop through the elements field:

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

In order to tell angular cli that elements has a property of controls (so of type FormArray), you need to format it in your ts logic code as the following (implement a getter for elements field):

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

Upvotes: 1

Andriy
Andriy

Reputation: 15442

your t is of type FormArray, FormArray.controls array is of type AbstractControl[], thus, each ticket at

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

line is of type AbstractControl, which does not have controls property as is seen in TS error in your screenshot. TS does not know that each ticket actually is of type FormGroup (set here this.t.push(this.formBuilder.group({...}) and which has controls property).

So you can try to add another getter tControls:

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

and use it within *ngFor:

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

Please note, that now [formGroup] will also be properly filled with FormGroup and not AbstarctControl

One of your Angular upgrades probably added

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

to your tsconfig.json file, you can verify it just by setting these values to false and rebuilding your app, but I recommend to leave these strict checks.

Upvotes: 1

cat tourist
cat tourist

Reputation: 249

'controls' isn't a property of an AbstractControl. instead you can use your form group, so 'dynamicForm.controls.controlName'

Upvotes: 0

Related Questions