0
votes

I have a tag in HTML, which displays calendar:

 <mwl-calendar-month-view
    *ngSwitchCase="'month'"
    [viewDate]="viewDate"
    [events]="eventsValue"
  >

"eventsValue" is a getter for CalendarEvent[] value. I get my calendar events via REST call. Then I subscribe to acquired observable. Inside "subscribe" I do some logic and create new CalendarEvent[] based on the response. Then I assign the newly created variable to he variable which is used in HTML file. What I'd expect is that when the value of variable used in HTML changes then the view is refreshed. But the effect is that calendar tries to be refreshed, but it happens in the moment when I call "subscribe" on my observable from REST call. Any ideas how can I have the updated value of events properly refreshed and have it visible in view? Function to call REST and update CalendarEvents[]:

  public fetchCalendarData() {
    const loggedUser = this.userService.getLoggedUser();
    if (loggedUser) {
      this.calendarService.fetchCalendarData(loggedUser).subscribe((response) => {

        // some logic with response

        this.eventsValue = [{
          title: 'title',
          start: new Date(),
          end: new Date()
        }];
      });
    }
  }

Screenshot from debug to see when calendar view tries to refresh itself (I guess it's the moment when I get the warning about "events" being "undefined"): debug - calendar refresh moment

Then after executing "subscribe" I called "this.events" in console I don't understand why it's still undefined (I just saw the value being updated in "subscribe").

3
Are you able to create a sample-application on stackblitz.com or post the relevant bits of the component including the definition of the events and eventsValue properties? You are assigning to eventsValue but reading from events? Also, is your Component defined using OnPush change-detection or Default? - Clemens Sum

3 Answers

0
votes

Try injecting a reference to the components ChangeDetector and explicitly trigger change-detection by calling detectChanges() (to run change-detection from the component and all its children) or markForCheck() (to mark the components and all parent components up to root for change-detection).

constructor(private changeDetectorRef: ChangeDetectorRef) {}

---8<----

public fetchCalendarData() {
    const loggedUser = this.userService.getLoggedUser();
    if (loggedUser) {
      this.calendarService.fetchCalendarData(loggedUser).subscribe((response) => {

        // some logic with response

        this.eventsValue = [{
          title: 'title',
          start: new Date(),
          end: new Date()
        }];

        // trigger change-detection
        this.changeDetectorRef.detectChanges();
      });
    }
  }

To prevent the mwl-calendar-month-view to complain about undefined [events] input:

<ng-container *ngIf="eventsValue">
    <mwl-calendar-month-view
        *ngSwitchCase="'month'"
        [viewDate]="viewDate"
        [events]="eventsValue"
    >
</ng-container>
0
votes

Based on @Clemens Sum comment I changed changeDetection in my @Component annotation from ChangeDetectionStrategy.OnPush to ChangeDetectionStrategy.Default and it worked. Thanks!

0
votes

None of the answers above worked for me. However, I found a solution.

mwl-calendar has a refresh property, which takes a Subject as a value. Emitting a value to the Subject will trigger the refresh action.

The following example has a monthly view with previous/today/next buttons and clickable days. Clicking a day will add an event and refresh the calendar view. I am using Bootstrap 5 for the CSS.

calendar.component.html

<div class="calendar">
  <h1>{{viewDate | date: 'MMMM'}}</h1>
  <div class="row text-center">
    <div class="col-md-4">
      <div class="btn-group">
        <div class="btn btn-primary" mwlCalendarPreviousView [view]="view" [(viewDate)]="viewDate">Previous</div>
        <div class="btn btn-outline-secondary" mwlCalendarToday [(viewDate)]="viewDate">Today</div>
        <div class="btn btn-primary" mwlCalendarNextView [view]="view" [(viewDate)]="viewDate">Next</div>
       </div>
     </div>
   </div>
   <mwl-calendar-month-view [viewDate]="viewDate (dayClicked)="dayClicked($event.day)" [events]="events" [refresh]="refreshCalendar"></mwl-calendar-month-view>
</div>

calendar.component.ts

import { Component, OnInit } from '@angular/core';
import { CalendarEvent, CalendarView } from 'angular-calendar';
import { Subject } from 'rxjs';

export class CalendarComponent implements OnInit {

  viewDate: Date = new Date();
  view: CalendarView = CalendarView.Month;
  CalendarView = CalendarView;
  events: CalendarEvent[] = [];
  refreshCalendar: Subject<void> = new Subject();

  ...

  dayClicked({ date, events }: { date: Date; events: CalendarEvent[] }) {
    this.events.push({
      start: date,
      title: 'Some title'
    });
    this.refreshCalendar.next();
  }

The result should look like this:

Example showcase