2 way binding ngmodel to a 2d array is giving undefined when dynamically populating the array

45 Views Asked by At

I want to use [(ngModel)] bound to a 2d boolean array as I have a nested ngFor loop in the html. I want to populate this array dynamically as data will be coming from database but as the html starts to access the data before the array has been populated, it ends up giving me an undefined error.

Html Code

<div *ngFor="let item of DriveDateSlots;let indexOfDate = index">
    <div *ngFor="let Slotitem of getTimeSlotDateWise(item.driveSlotDate);let indexOfSlot = index">
        <mat-slide-toggle [(ngModel)]="isSlotHidden[indexOfDate][indexOfSlot]">Hide</mat-slide-toggle>
    </div>
</div> 

Declarations

isSlotHidden: boolean[][] = [[]];
DriveSlot: any = [];

ts code

GetAllDriveSlots(): any {
    this.DriveSlot = [];
    this.masterservice.GetAllDriveSlotDetail(this.DriveID).subscribe((response: any) => {
        this.DriveSlot = response;
        let k = 0;
        const uniqueDates = [...new Set(this.DriveSlot.map( obj => obj.driveSlotDate ))];
        for(let i=0;i<uniqueDates.length;i++)
        {
            let j=0;
            while(k < this.DriveSlot.length && this.DriveSlot[k].driveSlotDate == uniqueDates[i])
            {
                this.isSlotHidden[i][j]= false;
                j++;
                k++;
            }
        }
    },
    (error: any) => {
        console.log("Error");
    })
}

the ts function is called inside ngOnInit. I am not sure how I can resolve this as the html does not wait for the ts function to complete. Currently I am just populating the 2d array with false but I plan on getting data from database to populate it in the future.

I have tried initialising it with dummy data during declaration and it worked fine but since the number of rows and columns are not known. This can definitely cause some trouble in the future.

1

There are 1 best solutions below

1
gaston chatelet On

You can try not to initialize DriveSlot as an empty array:

DriveSlot: any = [];

.. instead, just declare it:

DriveSlot: any;

And in the html file, use tthe ngIf on a container of tthe ngFor:

<div *ngIf="DriveSlot">
    <div *ngFor="let item of DriveDateSlots;let indexOfDate = index">
        <div *ngFor="let Slotitem of getTimeSlotDateWise(item.driveSlotDate);let indexOfSlot = index">
            <mat-slide-toggle [(ngModel)]="isSlotHidden[indexOfDate][indexOfSlot]">Hide</mat-slide-toggle>
        </div>
    </div> 
</div> 

With his aproach, you only render the html code when the suscription ends and you initialize DriveSlot with the response