While I am not very familiar with using full calendar, after skimming through their documentation, I came across some interesting insights. It seems that the API of this plugin may not be its strongest feature, but ultimately the choice is yours to make.
One key point in the docs mentions an event that triggers each time the view changes. This means that while the view will render smoothly, any skipping might not be visibly noticeable. To navigate across the calendar, you would need to create your own methods to determine if you are moving forward or backward (see example). You can experiment with this approach by checking out this link: https://codepen.io/prowseed/pen/bKQEov?editors=0010
var lastOperationFlag;
$('#calendar').fullCalendar({
events: [...],
header: false, // hide the default header
viewRender: function (view, element) {
var start = view.start._i; // timestamp of current view's beginning
var end = view.end._i; // timestamp of current view's end
var events = view.options.events; // all events
if( checkBoundariesAndCurrentRange(start, end, events) ){
(lastOperationFlag === 'next') ? $('#calendar').fullCalendar('next') : $('#calendar').fullCalendar('prev');
}
}
});
$('#prev').on('click', function() {
lastOperationFlag = 'prev';
$('#calendar').fullCalendar('prev'); // move to previous view
});
$('#next').on('click', function() {
lastOperationFlag = 'next';
$('#calendar').fullCalendar('next'); // move to next view
});
function checkBoundariesAndCurrentRange (start, end, events) {
if (events.length === 0) return false;
var smallestDate = null;
var biggestDate = null;
var eventsInRange = false;
events.forEach(e => {
var ev_start = (new Date(e.start)).getTime(); // consider using momentjs for safer transformation
if (smallestDate == null || ev_start < smallestDate) smallestDate = ev_start;
if (biggestDate == null || ev_start > biggestDate) biggestDate = ev_start;
if (start <= ev_start && end >= ev_start) eventsInRange = true;
});
console.log((!eventsInRange && smallestDate < start && biggestDate > end) )
return (!eventsInRange && smallestDate < start && biggestDate > end)
}