Filtering dates for Angular Material Calendar based on two lists received from async sources

619 Views Asked by At

I want to disable certain dates on a Material Calendar. These dates come from two sources. The first from inside an object(camper) provided as input. The second is an api call that return a list of bookings based on the camper ID. The first one is read out no problem, and the dates are disabled accordingly.

The problem is with the api call. I think it happens later and the filter doesn't wait till it is finished. I have been trying different ways to get the filter to wait (promise, await, fork join), but he still doesn't wait, or no dates get disbled at all.

The expected result for this camper would be 2 periods of disabled dates on calendar.

  • 12/06 to 15/06 (blocked dates) <- showing
  • 21/06 to 24/06 (booked dates) <- not showing

I would like help finding a way so the filter waits until the full list of dates is collected.

component.html

  <div class="calendar-wrapper">
    <mat-calendar
      #calendar
      (monthSelected)="handleMonthSelected($event)"
      (selectedChange)="onSelect($event)"
      [comparisonStart]="this.selectedDateRange.start"
      [comparisonEnd]="this.selectedDateRange.end"
      [selected]="selectedDateRange"
      [dateFilter]="blockedDatesFilter"
      >
    </mat-calendar>
  </div>

component.ts

export class CamperBookingDetailsComponent implements AfterContentInit {
  @Input() camper!: Camper;
  @ViewChild('calendar') calendar!: MatCalendar<Date>;

  blockedDates = (): Date[] => {
      let tempBlockedDates: Date[] = [];
      Object.entries(this.camper.difPrizes).forEach(([key, value]) => {
        if (value === 0) {
          tempBlockedDates.push(new CamperDate(new Date(key)));
        }
      });

      this._bookingService.getBookings$({"camperId": this.camper._id}).subscribe(bookings => {
        bookings.forEach(booking => {

          this.getDates(new Date(booking.startDate), new Date(booking.endDate)).forEach(date => {
            tempBlockedDates.push(date);
          });
        });
      });
      return tempBlockedDates;
  }
  blockedDatesFilter = (d: Date): boolean => {
    console.log(this.blockedDates());
    const time = d.getTime();
    return !this.blockedDates().find(x => x.getTime() == time);
  };

      constructor(private _renderer: Renderer2, private _bookingService: BookingService) {}
}

I also tried following async code. This doesn't work because the Material Calendar does not accept (d: Date) => Promise.

  blockedDates = async (): Promise<Date[]> => {
    let tempBlockedDates: Date[] = [];
    Object.entries(this.camper.difPrizes).forEach(([key, value]) => {
      if (value === 0) {
        tempBlockedDates.push(new CamperDate(new Date(key)));
      }
    });

    await this._bookingService.getBookings$({"camperId": this.camper._id}).subscribe(bookings => {
      bookings.forEach(booking => {
        this.getDates(new CamperDate(booking.startDate), new CamperDate(booking.endDate)).forEach(date => {
          tempBlockedDates.push(date);
        });
      });
    });

    return tempBlockedDates;
  }
  blockedDatesFilter = async (d: Date): Promise<boolean> => {
    console.log(this.blockedDates());
    const time = d.getTime();
    const blockedDates = await this.blockedDates();
    return !blockedDates.find(x => x.getTime() == time);
  };

Console log from inside blockedDatesFilter = (d: Date): boolean:

(4) [Sun Jun 12 2022 00:00:00 GMT+0200 (Central European Summer Time), Mon Jun 13 2022 00:00:00 GMT+0200 (Central European Summer Time), Tue Jun 14 2022 00:00:00 GMT+0200 (Central European Summer Time), Wed Jun 15 2022 00:00:00 GMT+0200 (Central European Summer Time)]
0: Sun Jun 12 2022 00:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
1: Mon Jun 13 2022 00:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
2: Tue Jun 14 2022 00:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
3: Wed Jun 15 2022 00:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
4: Tue Jun 21 2022 01:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
5: Wed Jun 22 2022 01:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
6: Thu Jun 23 2022 01:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
7: Fri Jun 24 2022 01:00:00 GMT+0200 (Central European Summer Time) {_status: 'available', _price: 0}
length: 8
[[Prototype]]: Array(0)

Material Calendar: Material Calendar

1

There are 1 best solutions below

2
On

you didn't list your async code, so I don't know exactly what you have tried.

so you tried this?

blockedDatesFilter = async (d: Date): boolean => {
   console.log(this.blockedDates());
   const time = d.getTime();
   const blockedDates = await blockedDates();
   return !blockedDates.find(x => x.getTime() == time);
};