Reputation: 1873
I have converted an app from angular 8 to angular14 I have a form array that is suddenly giving this error
cfs-detail.component.html:13 ERROR TypeError: Cannot read properties of null (reading '_rawValidators') at getControlValidators (forms.mjs:901:20) at setUpValidators (forms.mjs:3065:24) at setUpFormContainer (forms.mjs:3182:5) at FormGroupDirective._setUpFormContainer (forms.mjs:4996:9) at FormGroupDirective.addFormGroup (forms.mjs:4883:14) at FormGroupName.ngOnInit (forms.mjs:3732:28) at callHook (core.mjs:2498:22) at callHooks (core.mjs:2467:17) at executeInitAndCheckHooks (core.mjs:2418:9) at selectIndexInternal (core.mjs:9826:17)
The array does not render correctly. Here is a picture of how it initially loads. Tabbing through the controls seems to make it behave better until you eventually get to something that looks correct.
This is what I am expecting. It is a CSS grid. The CSS was correct before the angular upgrade. I am pretty sure this is something I did trying to make all the 'initial value errors go away.
Here it the HTML template
<ng-template #loading>
<div >loading...</div>
<div *ngIf="!year">please pass in year</div>
<div *ngIf="!showBy">please pass in periodChoice!</div>
<div *ngIf="!myPeriods">periods have not loaded</div>
</ng-template>
<span *ngIf="showBy ; else loading">
<span *ngIf="year ; else loading">
<div class="year">
<button (click)="toggleForm()" id="btnToggle">{{toggleFormText}}</button>
{{year}}
</div>
<div *ngIf="myPeriods as periods ; else loading " class="cfs-12month-grid {{showBy}} y{{year}}">
<ng-container [formGroup]="myFormGroup">
<ng-container formArrayName="periods" >
<ng-container *ngFor="let perFrm of periods12.controls ;let i = index;" formGroupName="i" >
<p class="fieldlabel cfs {{showBy}} {{monthShortName(myPeriods[i])}}">{{shortDate(myPeriods[i]) }}
</p>
<input
class="fieldvalue cfs {{showBy}} {{ monthShortName(myPeriods[i]) }}"
type="text" value="{{roundedAmount(myPeriods[i])}}"
formControlName="Amount"
/>
</ng-container>
</ng-container>
</ng-container>
</div>
</span>
</span>
Here is the component code
import { Component, OnInit , AfterViewInit
, Input, Output, SimpleChanges
, ElementRef, EventEmitter, ViewChild} from '@angular/core';
import { AbstractControl , FormBuilder, FormGroup
, Validators
, RequiredValidator, MaxLengthValidator, MinLengthValidator, FormControl, FormArray
} from '@angular/forms';
import { Observable } from 'rxjs';
import { Tools } from '../../tools';
import { CashFlowStringPeriod } from '../cash-flow-string-period';
import { cashFlowStringService } from '../services/cash-flow-string.service';
import { cashFlowStringPeriodService } from '../services/cash-flow-string-period.service';
@Component({
selector: 'app-cfs-12months',
templateUrl: './cfs12-months.component.html',
styleUrls: ['./cfs12-months.component.css']
})
export class cfs12MonthsComponent implements OnInit {
@Input() showBy : string="byQtr";
@Input() cfsPeriods : CashFlowStringPeriod[];
@Input() year : number;
myFormGroup : FormGroup; //do not 'strong type' this
//2020 10 25 gregm its making me strong type it...
toggleFormText:string="-";
toggleFormVisible:number=1;
public myPeriods : CashFlowStringPeriod[]=[];
formatter_shortMonth = new Intl.DateTimeFormat('default', { month: 'short' });
constructor(private myFormBuilder: FormBuilder
, private cfsService : cashFlowStringService
, private cfspService : cashFlowStringPeriodService ) { }
ngOnInit(): void {
}
buildForm(){
this.myFormGroup = this.myFormBuilder.group(
{
//simply add a formArray to the group
periods : this.myFormBuilder.array([])
}
,{ updateOn: "blur" }
);
this.myFormGroup.valueChanges.subscribe((data: any) => {
this.saveMainForm();
});
} //end buildForm
get periods12() {
return this.myFormGroup.get("periods") as FormArray;
}
populateForm(){
console.log('cf12pf pCount',this.myPeriods.length);
this.myPeriods.forEach( cfsp =>{
const periodForm = this.myFormBuilder.group({
id : [cfsp.id, Validators.required]
, cashFlowId : [cfsp.cashFlowId, Validators.required]
, FlowDate : [cfsp.FlowDate, Validators.required]
, Amount : [cfsp.Amount, Validators.required]
});
this.periods12.push(periodForm);
} //callback
);// forEach
console.log('leave pf', this.periods12);
}
filterMyPeriods(){
this.myPeriods = this.cfsPeriods.filter( cfsp =>
{
let d:Date = this.getDateFromStringOrObject(cfsp.FlowDate);
return (this.year == d.getFullYear()) ;
}
);
let f=1;
}
getDateFromStringOrObject(input_ : any) : Date{
let s: string="";
if (typeof input_ === 'object'){
s= input_.formatted;
}else{
s=input_;
}
let d:Date = new Date(s);
return d;
}
public monthShortName (cfsp_ : CashFlowStringPeriod) : string {
let d= this.getDateFromStringOrObject(cfsp_.FlowDate) ;
let s:string =this.formatter_shortMonth.format(d).toLowerCase();
console.log("month SN",s);
return s;
}
public roundedAmount( cfsp_ : CashFlowStringPeriod) : number{
return Tools.roundToNplaces(cfsp_.Amount,2);
}
formatter_shortDate = new Intl.DateTimeFormat( );
shortDate( cfsp_ : CashFlowStringPeriod) : string {
let d= this.getDateFromStringOrObject(cfsp_.FlowDate) ;
let s:string = this.formatter_shortDate.format(d);
console.log("shortdate",s);
return s;
}
}
Upvotes: 1
Views: 2983
Reputation: 1873
Hopefully this helps someone in the future. There are no results when searching the title of the question...
My mistake was a simple and aggravating one.
formGroupName does not = 'i', it should equal the value of i.
so
<ng-container *ngFor="let perFrm of periods12.controls ;let i = index;" formGroupName="i" >
should be ( square brackets around formGroupName )
<ng-container *ngFor="let perFrm of periods12.controls ;let i = index;" [formGroupName]="i" >
I can not remember which error messages led me to tinkering w/ the *ngFor statements. I believe it was related to variables now requiring initialization.
Upvotes: 4