fullcalendar: viewDidMount is not being triggered when toggling between timeGridWeek and timeGridDay views

Bug Reports

I’ve noticed that viewDidMount does not appear to be triggered when navigating between the timeGridWeek and timeGridDay views. It does, however, get triggered when navigating between the other views.

React/Vue/Angular/etc

This bug is observed with the React version of FullCalendar.

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 14
  • Comments: 20 (2 by maintainers)

Most upvoted comments

As of v5, when switching between views of the same parent type, the DOM will be reused and the viewDidMount/WillUnmount will NOT fire.

I need to document this better.

@arshaw I had been using this to change the firstDay option dynamically because the view-specific options doesn’t seem to read this value. I want dayGridWeek to start with today and dayGridMonth to start with Sunday.

            views: {
                dayGridWeek: {
                    firstDay: moment().toDate().getDay(),
                    weekends: false,
                },
                dayGridMonth: {
                    firstDay: 0,
                    fixedWeekCount: false,
                    weekends: false,
                }
            },
            viewDidMount: function (info) {
                if (info.view.type == 'dayGridWeek') {
                    info.view.calendar.setOption('firstDay', moment().toDate().getDay());
                } else if (info.view.type == 'dayGridMonth') {
                    info.view.calendar.setOption('firstDay', 0);
                }
            },

As of right now, neither option is working in v5, but it worked for v3 and v4.

EDIT 1: The above code keeps “today” as first day when ‘initialView’ is ‘dayGridWeek’.

EDIT 2: I fixed my issue by hacking the viewClassNames hook mentioned above, but it definitely feels like a hack.

            viewClassNames: function (info) {
                if (info.view.type == 'dayGridWeek') {
                    info.view.calendar.setOption('firstDay', moment().toDate().getDay());
                } else if (info.view.type == 'dayGridMonth') {
                    info.view.calendar.setOption('firstDay', 1);
                }

                return [];
            },

I’m seeing this with dayGridMonth to dayGridWeek as well.

Is there another render hook to use that will have a similar effect? For a variety of reasons I have to display the view title elsewhere in my template and was trying to use this hook to update it.

EDIT: I see that you can use the viewClassNames hook to do this.

As of v5, when switching between views of the same parent type, the DOM will be reused and the viewDidMount/WillUnmount will NOT fire.

I need to document this better.

For anyone still experiencing this issue, I managed to solve it by using custom buttons, instead of the ones provided by the plugins.

headerToolbar={{
  left: 'prev,next today',
  center: 'title',
  right: 'dayGridMonthCustom,timeGridWeekCustom,timeGridDayCustom'
}}

customButtons={{
  dayGridMonthCustom: {
    text: "Your translatedText",
    click: () => {
      fullCalendar?.getApi().changeView('dayGridMonth')
      // rest of your code here
    }
  },
  timeGridWeekCustom: {
    text: "Your translated text",
    click: () => {
      fullCalendar?.getApi().changeView('timeGridWeek')
      // rest of your code here
    }
  },
  timeGridDayCustom: {
    text: "Your translated text",
    click: () => {
      fullCalendar?.getApi().changeView('timeGridDay')
      // rest of your code here
    }
  },
}}

datesSet={onDateChage}

This way you stop relying on the built-in eventHandler ‘viewDidMount’ (which doesn’t work properly) and can manually fix the issue 😃

I needed to move the calendar to the current day when moving from ‘resourceTimelineDay’ to ‘resourceTimelineWeek’.

I hijacked the viewClassNames hook, but found I still had to put the scrollToTime in a setTimeout , perhaps due to the order in which the hooks are triggered.

  const handleViewClassNames = viewArgs => {
    switch (viewArgs.view.type) {
      case 'resourceTimelineWeek':
        setTimeout(() => {
          viewArgs.view.calendar.scrollToTime({ day: new Date().getDay() - 1 });
        });
        break;
      default:
    }

    return classes.root; // don't forget the real reason for this hook!
  };

Update: I cannot recommend this solution anymore. viewClassNames callback fires far too often, causing the calendar to constantly snap back to the current day when doing things like dragging an event to another day.