I am using the FullCalendar JavaScript library (version 5) from https://fullcalendar.io. Previously, I had used the events
property of the calendar and pointed that to a JavaScript function. But I have several different event types. Each of the event types is styled on the calendar differently, and I would like to implement a show/hide functionality for each event type down the road. For these reasons I am trying to utilize eventSources
. My problem is that the calendar does not display any of the events from the eventSource that I pass it.
I am keeping things simple for now as I try to get things working. My JavaScript code:
$(document).ready(function() {
var calendar = new FullCalendar.Calendar($('#calendar')[0], {
initialView: 'dayGridMonth',
eventSources: [
{
url: '/com/modules/calendar.cfc?method=getNofas',
failure: function() {
console.log('error fetching nofas');
},
color: 'green'
}
]
});
calendar.render();
});
Below is a sample of the JSON data returned by my ColdFusion function (as specified in the above URL) as shown when I dig through the response information in the browser tools. Right now I only have a single event.
[{"id":1,"title":"Test NOFA 1","start":"March, 22 2023 12:00:00 -0600","end":""}]
I do not get any messages in the console indicating any type of failure, but the calendar remains blank. Does anyone have any suggestions? Would this have anything to do with FullCalendar not "waiting" for the results of the ColdFusion function call before rendering?
So I figured it out. I think I was incorrectly trying to set my event.start
property to an integer value from Date.getTime()
. It needed the actual Date object. Thanks go out to @ADyson for nudging me in the right direction.
The code in the original post was a very striped down version of the finished product, as I was just trying to get the bare minimum working before I re-added all the other stuff. I am posting the entire JavaScript code here in the event that it could be helpful to anyone else down the road. The page has five toggle switches at the top that are used to show or hide the various event types. The switch values are stored in sessionStorage
so that they can persist between page refreshes. The calendar items have tooltips so that you can peek at the entire title of an event if it gets cut off in the calendar.
<script src='https://unpkg.com/tooltip.js/dist/umd/tooltip.min.js'></script>
// Tooltips also require popper.js, but that's been included prior to this file
<script>
const nofaForegroundColor = '#FFF';
const nofaBackgroundColor = '#3CB371';
const pendingRfcForegroundColor = '#FFF';
const pendingRfcBackgroundColor = '#717D7E';
const rfcForegroundColor = '#000000';
const rfcBackgroundColor = '#F39C12';
const outageForegroundColor = '#000000';
const outageBackgroundColor = '#F08080';
const eventForegroundColor = '#FFF'
const eventBackgroundColor = '#5499C7'
function loadSwitchValue(switchID) {
var storedValue = undefined;
switch(switchID) {
case 'nofa':
storedValue = sessionStorage.getItem('rangeChangeMgmtCalendarNofaToggle');
break;
case 'pendingRfc':
storedValue = sessionStorage.getItem('rangeChangeMgmtCalendarPendingRfcToggle');
break;
case 'rfc':
storedValue = sessionStorage.getItem('rangeChangeMgmtCalendarRfcToggle');
break;
case 'outage':
storedValue = sessionStorage.getItem('rangeChangeMgmtCalendarOutageToggle');
break;
case 'event':
storedValue = sessionStorage.getItem('rangeChangeMgmtCalendarEventToggle');
}
if(storedValue == 'true' || storedValue == null) {
return true;
} else {
return false;
}
}
function saveSwitchValue(switchID, value) {
switch(switchID) {
case 'nofa':
sessionStorage.setItem('rangeChangeMgmtCalendarNofaToggle', value);
break;
case 'pendingRfc':
sessionStorage.setItem('rangeChangeMgmtCalendarPendingRfcToggle', value);
break;
case 'rfc':
sessionStorage.setItem('rangeChangeMgmtCalendarRfcToggle', value);
break;
case 'outage':
sessionStorage.setItem('rangeChangeMgmtCalendarOutageToggle', value);
break;
case 'event':
sessionStorage.setItem('rangeChangeMgmtCalendarEventToggle', value);
}
}
$(document).ready(function() {
var calendarRendered = false;
// Load previous switch values
$('#nofaSwitch').prop('checked', loadSwitchValue('nofa'));
$('#pendingRfcSwitch').prop('checked', loadSwitchValue('pendingRfc'));
$('#rfcSwitch').prop('checked', loadSwitchValue('rfc'));
$('#outageSwitch').prop('checked', loadSwitchValue('outage'));
$('#eventSwitch').prop('checked', loadSwitchValue('event'));
// Declare, initialize, and render the calendar
var calendar = new FullCalendar.Calendar($('#calendar')[0], {
initialView: 'dayGridMonth',
editable: false,
themeSystem: 'bootstrap',
customButtons: {
btnAddEvent: {
text: 'Add Special Event',
click: function() {
alert('clicked');
}
}
},
headerToolbar: {
start: 'prev,today,next',
center: 'title',
right: 'btnAddEvent'
},
eventDidMount: function(info) {
$(info.el).tooltip({
title: info.event.title,
placement: 'top',
trigger: 'hover',
container: 'body'
});
},
events: function(info, successCallback, failureCallback) {
$.get('/com/modules/calendar.cfc?method=getCalendarEvents&output=json&start=' + info.start.valueOf() + '&end=' + info.end.valueOf() + '&nofas=' + $('#nofaSwitch')[0].checked + '&pendingRfcs=' + $('#pendingRfcSwitch')[0].checked + '&rfcs=' + $('#rfcSwitch')[0].checked + '&outages=' + $('#outageSwitch')[0].checked + '&events=' + $('#eventSwitch')[0].checked, function(data) {
var jsData = (JSON.parse(data)).dataset.row;
for(var i = 0; i < jsData.length; i++) {
switch(jsData[i].type) {
case 'nofa':
jsData[i].url = '/nofa.cfm?id=' + jsData[i].id;
jsData[i].id = i;
jsData[i].color = nofaForegroundColor;
jsData[i].backgroundColor = nofaBackgroundColor;
jsData[i].start = new Date(Date.parse(jsData[i].start));
jsData[i].allDay = true;
break;
case 'pendingRfc':
jsData[i].url = '/rfc.cfm?id=' + jsData[i].id;
jsData[i].id = i;
jsData[i].color = pendingRfcForegroundColor;
jsData[i].backgroundColor = pendingRfcBackgroundColor;
jsData[i].start = new Date(Date.parse(jsData[i].start));
jsData[i].allDay = true;
break;
case 'rfc':
jsData[i].url = '/rfc.cfm?id=' + jsData[i].id;
jsData[i].id = i;
jsData[i].color = rfcForegroundColor;
jsData[i].backgroundColor = rfcBackgroundColor;
jsData[i].start = new Date(Date.parse(jsData[i].start));
jsData[i].allDay = true;
break;
case 'outage':
jsData[i].url = '/outage.cfm?id=' + jsData[i].id;
jsData[i].id = i;
jsData[i].color = outageForegroundColor;
jsData[i].backgroundColor = outageBackgroundColor;
jsData[i].start = new Date(Date.parse(jsData[i].start));
jsData[i].allDay = true;
break;
case 'event':
jsData[i].url = jsData[i].id;
jsData[i].id = i;
jsData[i].color = outageForegroundColor;
jsData[i].backgroundColor = outageBackgroundColor;
jsData[i].start = new Date(Date.parse(jsData[i].start));
jsData[i].end = new Date(Date.parse(jsData[i].end));
jsData[i].allDay = true;
}
}
successCallback(jsData);
});
}
});
calendar.render();
calendarRendered = true;
$('#nofaSwitch, #pendingRfcSwitch, #rfcSwitch, #outageSwitch, #eventSwitch').change(function(eventData) {
switch(eventData.target.id) {
case 'nofaSwitch':
saveSwitchValue('nofa', eventData.currentTarget.checked);
break;
case 'pendingRfcSwitch':
saveSwitchValue('pendingRfc', eventData.currentTarget.checked);
break;
case 'rfcSwitch':
saveSwitchValue('rfc', eventData.currentTarget.checked);
break;
case 'outageSwitch':
saveSwitchValue('outage', eventData.currentTarget.checked);
break;
case 'eventSwitch':
saveSwitchValue('event', eventData.currentTarget.checked);
}
if(calendarRendered == true) {
calendar.refetchEvents();
}
});
});
</script>