greg
greg

Reputation: 1873

Cannot read properties of null (reading '_rawValidators')

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.

picture of form array with problem

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 is the form array as it should appear

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

Answers (1)

greg
greg

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

Related Questions