I have fullcalendar 4.3.1 working properly when only 1 calendar is on the page, however when I put 3 calendars on the page, only the last one refreshes properly when clicking a date or drag selecting several dates. I have to click the refresh button to get the first or second calendars to refresh.
Here is a video demonstrating the issue... calendar-refresh-issue.mov
I am assigning a unique id to each calendar using the data-id and a custom attribute...
data-id="calendar-3"
calendar-id="calendar-3"
Here is the init method that fires for each calendar loaded...
init() {
var calendarEl = this.template.querySelector(`[data-id="${this.calendarId}"]`);
// eslint-disable-next-line no-undef
this.calendar = new FullCalendar.Calendar(calendarEl, {
plugins: ["dayGrid", "timeGrid", "list","interaction","moment"],
views: {
listDay: { buttonText: "list day" },
listWeek: { buttonText: "list week" },
listMonth: { buttonText: "list month" },
timeGridWeek: { buttonText: "week time" },
timeGridDay: { buttonText: "day time" },
dayGridMonth: { buttonText: "month", eventLimit:4 },
dayGridWeek: { buttonText: "week" },
dayGridDay: { buttonText: "day" }
},
eventRender: info => {
if (info.view.type === 'listMonth') {return}
let eventEl = info.el.querySelector('.fc-content');
let eventID = info.event.id;
let link = document.createElement('a');
let linkIcon = document.createElement('i');
link.id = eventID;
let colors = {
backgroundColor: info.event.backgroundColor,
borderColor: info.event.borderColor,
textColor: info.event.textColor
}
if(self.colorState === false) {
colors.backgroundColor = '#fff';
colors.borderColor = '#000';
colors.textColor = '#000';
}
if(info.event.extendedProps.status === 'Confirmed') {
linkIcon.classList.add('float-right', 'fa', 'fa-thumbs-up');
linkIcon.style.color = colors.textColor;
linkIcon.style.paddingRight = '3px';
linkIcon.style.fontSize = 'medium';
}
else if(info.event.extendedProps.status === 'Unconfirmed') {
linkIcon.classList.add('float-right', 'fa', 'fa-thumbs-o-up');
linkIcon.style.color = colors.textColor;
linkIcon.style.paddingRight = '3px';
linkIcon.style.fontSize = 'medium';
}
eventEl.style.padding = '3px';
eventEl.style.backgroundColor = colors.backgroundColor;
eventEl.style.color = colors.textColor;
eventEl.style.borderColor = colors.borderColor;
link.appendChild(linkIcon);
eventEl.insertBefore(link, eventEl.children[0]);
},
eventClick: info => {
if(this.mode !== 'Confirmation'
|| (this.shift === 'Available'
&& info.event.extendedProps.status === 'Availability'
&& info.event.extendedProps.providerId === this.providerId)) {
removeEvent({id: info.event.id}).then(result => {
if(result) {
info.event.remove();
}
else {
this.dispatchEvent(
new ShowToastEvent({
title: "Remove Shift Failed",
message: "Unable to remove event " + info.event.id,
variant: "error"
})
)
}
});
}
else {
let evt = {
eventId: info.event.id,
whoId: info.event.extendedProps.whoId,
whatId: info.event.extendedProps.whatId,
providerId: (this.shift === 'Claim' ? this.providerId : info.event.extendedProps.providerId),
status: 'Confirmed',
shift: info.event.extendedProps.shift,
title: (this.shift === 'Claim' ? this.title : info.event.title),
start: info.event.start,
end: info.event.end,
backgroundColor: '#006600',
borderColor: '#006600',
textColor: '#ffffff'
}
saveEvent({eventId: evt.eventId, whoId: evt.whoId, whatId: evt.whatId, providerId: evt.providerId, title: evt.title, startTime: evt.start, endTime: evt.end, allDayEvent: false, colorValue: evt.backgroundColor, borderColorValue: evt.borderColor, textColorValue: evt.textColor, status: evt.status, shift: evt.shift})
.then(result => {
if(result && result.error) {
console.log(result.error);
}
});
}
},
eventMouseEnter: info => {console.log("mouse enter", info)},
select: function(info) {
let allDayEvent = false;
let startDate, endDate;
if(self.mode === 'Scheduling' || self.shift === 'Available') {
console.log('selected ' + info.startStr + ' to ' + info.endStr);
if(!self.startTime || self.startTime === null){
allDayEvent = true;
startDate = new Date(info.startStr + 'T00:00:00');
endDate = new Date(info.endStr + 'T00:00:00');
}
else {
startDate = new Date(info.startStr + 'T' + self.startTime);
endDate = new Date(info.endStr + 'T' + self.endTime);
endDate = endDate.setDate(endDate.getDate() - 1);
}
for (let d = startDate; d < endDate; d.setDate(d.getDate() + 1)) {
let sd = d.toISOString();
let ed = sd.substring(0,10) + 'T' + (allDayEvent ? '00:00:00' : self.endTime);
self.createEvent(new Date(d), new Date(ed), allDayEvent);
}
}
},
dateClick:info => {
if(this.mode === 'Scheduling' || this.shift === 'Available') {
console.log("date click", info);
let allDayEvent = false;
let startDate, endDate;
if(!self.startTime || self.startTime === null){
allDayEvent = true;
startDate = new Date(info.dateStr + 'T00:00:00');
endDate = new Date(info.dateStr + 'T00:00:00');
}
else {
startDate = new Date(info.dateStr + 'T' + self.startTime);
endDate = new Date(info.dateStr + 'T' + self.endTime);
}
self.createEvent(startDate, endDate, allDayEvent);
}
},
eventReceive: info => {
let evt = {
eventId: info.event.id,
whoId: info.event.extendedProps.whoId,
whatId: info.event.extendedProps.whatId,
providerId: info.event.extendedProps.providerId,
status: info.event.extendedProps.status,
shift: info.event.extendedProps.shift,
title: info.event.title,
start: info.event.start,
end: info.event.end,
textColor: info.event.textColor,
backgroundColor: info.event.backgroundColor,
borderColor: info.event.borderColor
}
saveEvent({eventId: evt.eventId, whoId: evt.whoId, whatId: evt.whatId, providerId: evt.providerId, title: evt.title, startTime: evt.start, endTime: evt.end, allDayEvent: false, colorValue: evt.backgroundColor, borderColorValue: evt.borderColor, textColorValue: evt.textColor, status: evt.status, shift: evt.shift})
.then(result => {
if(result && result.error) {
console.log(result.error);
}
});
},
selectable: true,
selectMinDistance: 200,
height: this.height,
aspectRatio: this.aspectRatio,
defaultDate: this.defaultDate,
eventLimit: true,
editable: true,
droppable: true,
showNonCurrentDates: false,
header: false,
eventSources: [
{
events: this.eventSourceHandler,
id: `custom-${this.calendarId}`
},
],
});
this.calendar.render();
this.calendarLabel = this.calendar.view.title;
}
The refresh button logic is simple...
@api refresh() {
var eventSource = this.calendar.getEventSourceById(`custom-${this.calendarId}`);
eventSource.refetch();
}
I am using this in a series of salesforce lightning web components, but I don't believe this information is a factor since the calendar does work properly when only one is on the page.