4

Problem description:
There is an availability calendar which displays whether a person is busy on a particular slot (each day is divided to two slots). This state is stored in the isSlotFree boolean 2d array (this array is of size 31 x 2). Initially, all values in this array are initialized to true. Then, a http get request is made to a server requesting the busy dates. Once they are received, the function setIsSlotFree() is called to set the appropriate values in the array to false. In the view (HTML file) there is a <td> element for each slot. Each of these elements update their color (using class styles) based on the boolean value stored in the relevant index of the array. The problem is that the html page does not reflect the changes made to the array after calling the setIsSlotFree() function. (ie. the html elements still see all values as true). However, when I print the array in the console right after the get request, it has changed the appropriate values to false. When any event is triggered, then only the view is updated to the correct values. What is the problem here?

Following are the relevant parts of the component.ts file

export class CalendarComponent implements OnInit {

  viewDate: Date;
  isSlotFree: boolean[][] = [
    [true, true]
  ];

  constructor(private http: HttpClient) {

  }


  ngOnInit() {
    this.viewDate = new Date();
    var i: number;
    var j: number;

    for (i = 1; i < 31; i++) {
      this.isSlotFree.push([true, true]);
    }
    let p = new HttpParams().set('month', (this.viewDate.getMonth() + 1).toString());

    this.http.get < busyDateResponse[] > ("http://localhost:51967/api/stylists/getBusyDates", {
      params: p
    }).subscribe(res => {
      this.setIsSlotFree(res);
    });

    this.x = true;
    console.log(this.isSlotFree);
    this.viewDate = new Date();

  }

  setIsSlotFree(res: busyDateResponse[]): void {
    var busy_date: busyDateResponse;
    for (busy_date of res) {
      var temp: number = (busy_date.slot == 'm') ? 0 : 1;
      this.isSlotFree[busy_date.day - 1][temp] = false;
    }

  }
}

interface busyDateResponse {
  $id: string;
  day: number;
  month: number;
  year: number;
  slot: string;
}

Following shows the relevant parts of the component.html file

<ng-template #cellTemplate let-day="day" let-locale="locale">
  <div class="cal-cell-top">
    <div class="cal-day-number w3-xlarge">{{ day.date | calendarDate:'monthViewDayNumber':locale }}</div>
    <br>

  </div>
  <div *ngIf="day.inMonth && day.isFuture">
    <table style="width:100%">

      <tr>
        <td class="calendar-slot" [ngClass]="{'w3-green': isSlotFree[day.date.getDate()-1][0], 'w3-red': !isSlotFree[day.date.getDate()-1][0]}">{{isSlotFree[day.date.getDate()-1][0]}}Morning</td>
        <mat-checkbox (change)="editSelectedSlots($event)" [checked]="isSelectedSlot(day.date.getDate() + '_' + day.date.getMonth() + '_' + day.date.getFullYear() + '_m')?true:false" [id]="day.date.getDate() + '_' + day.date.getMonth() + '_' + day.date.getFullYear() + '_m'"
          *ngIf="isSlotFree[day.date.getDate()-1][0]"></mat-checkbox>
      </tr>
      <tr>
        <td class="calendar-slot" [ngClass]="{'w3-green': isSlotFree[day.date.getDate()-1][1], 'w3-red': !isSlotFree[day.date.getDate()-1][1]}">{{isSlotFree[day.date.getDate()-1][1]}}Evening</td>
        <mat-checkbox (change)="editSelectedSlots($event)" [checked]="isSelectedSlot(day.date.getDate() + '_' + day.date.getMonth() + '_' + day.date.getFullYear() + '_e')?true:false" [id]="day.date.getDate() + '_' + day.date.getMonth() + '_' + day.date.getFullYear() + '_e'"
          *ngIf="isSlotFree[day.date.getDate()-1][1]">
        </mat-checkbox>
      </tr>
    </table>
  </div>

</ng-template>

<div>
  <mwl-calendar-month-view [viewDate]="viewDate" [events]="events" (eventClicked)="eventClicked($event)" (dayClicked)="dayClicked($event)" [cellTemplate]="cellTemplate" [refresh]="refresh">
  </mwl-calendar-month-view>
  <div class="w3-center">
    <button mat-raised-button>Make booking</button>
  </div>
</div>

Please note that <mwl-calendar-month-view> utilizes the ng-template to generate cells in a calendar.

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133

1 Answers1

1

Well I finally found the solution after reading a lot about change detection in angular. The change detection strategy is executed before running the setIsSlotFree() function.Even though the values in the array are modified, the change detection strategy is not executed when the array values are changed by this function. Therefore, change detection needs to be executed manually after writing all the changes to the array. This can be done using ChangeDetectorRef.detectChanges() at the end of the setIsSlotFree() function.

If the constructor for the component is constructor(private http: HttpClient, private ref: ChangeDetectorRef) then,
the isSlotFree() function would look like,

setIsSlotFree(res:busyDateResponse[]):void {
    var busy_date:busyDateResponse;
    for(busy_date of res) {
        var temp:number = (busy_date.slot=='m')?0:1;
        this.isSlotFree[busy_date.day-1][temp] = false;
    }
    this.ref.detectChanges();        
  }
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>