FullCalendar.js
Powerful Calendar Management for Modern Web Applications
FullCalendar is a full-sized, drag & drop JavaScript event calendar for modern browsers. It's designed to be a highly customizable solution for displaying and managing events, appointments, and schedules in web applications.
In SmartAdmin, FullCalendar is integrated with a custom Bootstrap theme (fullcalendar.bootstrap.theme.js
) that ensures visual consistency with the rest of the application.
Installation
FullCalendar needs to be added to your project. Here's how to set it up:
1. Including Required Files
// Add the scripts as modules in your HTML
<link href="./pathTo/fullcalendar.min.css" rel="stylesheet">
<script type="module" src="./pathTo/fullcalendar.bundle.js"></script>
<script type="module" src="./pathTo/fullcalendar.bootstrap.theme.js"></script>
// Or import them in your JavaScript module
import { FullCalendar } from './pathTo/fullcalendar.bundle.js';
import './pathTo/fullcalendar.bootstrap.theme.js';
// Make sure to also include the CSS in your HTML or via a CSS loader
2. Initialize a Calendar
// After importing the modules as shown above
document.addEventListener('DOMContentLoaded', function() {
const calendarEl = document.getElementById('calendar');
const calendar = new FullCalendar.Calendar(calendarEl, {
themeSystem: 'bootstrap', // Use the SmartAdmin Bootstrap theme
initialView: 'dayGridMonth',
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek'
},
events: [
{
title: 'Meeting',
start: '2023-01-10T14:30:00',
end: '2023-01-10T16:30:00'
},
{
title: 'Conference',
start: '2023-01-11',
end: '2023-01-13'
}
]
});
calendar.render();
});
HTML Structure
<!-- Basic Calendar Container -->
<div id="calendar"></div>
<!-- Panel-Based Calendar Container (Recommended) -->
<div id="panel-1" class="panel">
<div class="panel-hdr">
<h2>Calendar <span class="fw-300"><i>View</i></span></h2>
<div class="panel-toolbar">
<button class="btn btn-panel" data-action="panel-collapse">
<!-- Panel controls -->
</button>
</div>
</div>
<div class="panel-container show">
<div class="panel-content">
<div id="calendar"></div>
</div>
</div>
</div>
- You need to include the FullCalendar files in your project - they are not automatically loaded.
- FullCalendar requires a container with a defined height. Without it, the calendar won't be visible.
- Make sure to include both the JavaScript modules and the CSS file.
- For more advanced documentation, refer to the official FullCalendar documentation.
SmartAdmin Bootstrap Theme
SmartAdmin includes a custom Bootstrap theme for FullCalendar that ensures visual consistency with the rest of the application. The theme is defined in fullcalendar.bootstrap.theme.js
.
// Excerpt from the bootstrap theme definition
class BootstrapTheme extends Theme {
// CSS classes for various elements
classes = {
root: 'fc-theme-bootstrap',
table: 'table table-calendar', // Uses Bootstrap table styling
tableCellShaded: 'table-active',
buttonGroup: 'btn-group',
button: 'btn btn-outline-default btn-sm',
buttonActive: 'active',
popover: 'popover',
popoverHeader: 'popover-header',
popoverContent: 'popover-body',
};
// Icon definitions using SmartAdmin icon system
baseIconClass = 'sa';
iconClasses = {
close: 'sa-close',
prev: 'sa-chevron-left',
next: 'sa-chevron-right',
prevYear: 'sa-angle-double-left',
nextYear: 'sa-angle-double-right',
};
}
sa-
prefix. This ensures all calendar controls match the rest of your application's design.
Configuration Options
FullCalendar offers extensive configuration options. Here are some of the most common ones:
Option | Type | Description |
---|---|---|
initialView |
String | The initial view when the calendar loads. Options: 'dayGridMonth', 'timeGridWeek', 'timeGridDay', 'listWeek' |
headerToolbar |
Object | Configuration for the calendar's header, with sections for left, center, and right |
events |
Array/Function/String | The events to display on the calendar. Can be an array of event objects, a function, or a URL |
editable |
Boolean | Whether the events can be dragged and resized |
selectable |
Boolean | Whether dates can be selected by clicking and dragging |
businessHours |
Object/Boolean | Emphasizes certain time slots on the calendar |
nowIndicator |
Boolean | Whether to show an indicator for the current time |
weekNumbers |
Boolean | Whether to show week numbers |
height |
Number/String/Function | Sets the height of the calendar. Can be 'auto', a pixel value, or 'parent' |
themeSystem |
String | The theme system to use. In SmartAdmin, set this to 'bootstrap' |
themeSystem: 'bootstrap'
to use the custom Bootstrap theme integration.
Event Handling
FullCalendar provides extensive event handling capabilities. Here's how to define and manage events:
Event Object Properties
// Basic event object structure
{
id: '123', // Unique identifier
title: 'Meeting with Client', // Event title
start: '2023-01-10T10:30:00', // Start date/time (ISO8601 format)
end: '2023-01-10T12:30:00', // End date/time (optional)
allDay: false, // Whether it's an all-day event
url: 'https://example.com', // Makes the event clickable as a link (optional)
className: 'bg-success', // CSS class names for styling (optional)
editable: true, // Whether this specific event is editable (optional)
extendedProps: { // Additional custom data (optional)
department: 'Marketing',
location: 'Conference Room A'
}
}
Event Sources
// Array of event objects
events: [
{ title: 'Event 1', start: '2023-01-01' },
{ title: 'Event 2', start: '2023-01-05', end: '2023-01-07' }
]
// JSON feed (AJAX)
events: '/api/events'
// Function that fetches events
events: function(info, successCallback, failureCallback) {
console.log('Fetching events for', info.startStr, 'to', info.endStr);
fetch('/api/events?start=' + info.startStr + '&end=' + info.endStr)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Loaded events:', data);
successCallback(data);
})
.catch(error => {
console.error('Error loading events:', error);
failureCallback(error);
});
}
// Multiple event sources with different colors
eventSources: [
{
url: '/api/events/team-a',
color: 'var(--success-500)', // All events from this source will be this color
textColor: 'white' // Text color for this source
},
{
url: '/api/events/team-b',
color: 'var(--info-500)',
textColor: 'white'
}
]
Event Callbacks
const calendar = new Calendar(calendarEl, {
// ...other options
// Triggered when an event is clicked
eventClick: function(info) {
alert('Event: ' + info.event.title);
// Change the background color of the event
info.event.setProp('backgroundColor', 'var(--danger-500)');
// To prevent default action (URL navigation)
info.jsEvent.preventDefault();
},
// Triggered when an event is dragged and dropped
eventDrop: function(info) {
if (!confirm("Are you sure you want to move this event?")) {
info.revert(); // Revert the change
} else {
// Update the event in your database
updateEventInDatabase(info.event);
}
},
// Triggered when an event is resized
eventResize: function(info) {
alert('Event has been resized. New end time: ' + info.event.end);
},
// Triggered when dates are selected by clicking and dragging
select: function(info) {
const title = prompt('Enter a new title for your event:');
if (title) {
calendar.addEvent({
title: title,
start: info.startStr,
end: info.endStr,
allDay: info.allDay
});
}
calendar.unselect(); // Clear selection
}
});
Advanced Features
API Methods
// Get a reference to the calendar
const calendar = new Calendar(calendarEl, options);
calendar.render();
// Navigate to different dates
calendar.next(); // Move to next month/week/day
calendar.prev(); // Move to previous month/week/day
calendar.today(); // Move to today
calendar.gotoDate('2023-05-01'); // Jump to a specific date
// Change views
calendar.changeView('timeGridWeek'); // Switch to week view
calendar.changeView('dayGridMonth'); // Switch to month view
// Event manipulation
const event = calendar.getEventById('123');
if (event) {
event.setProp('title', 'Updated Title'); // Update title
event.setStart('2023-01-12T10:00:00'); // Update start time
event.setEnd('2023-01-12T12:00:00'); // Update end time
event.setAllDay(true); // Make it an all-day event
event.setExtendedProp('status', 'confirmed'); // Update custom property
event.remove(); // Remove the event
}
// Add a new event
calendar.addEvent({
title: 'New Event',
start: '2023-01-15'
});
// Programmatically select dates
calendar.select('2023-01-24', '2023-01-26');
// Refetch events (if using dynamic source)
calendar.refetchEvents();
Localization
// Import the locale
import frLocale from '@fullcalendar/core/locales/fr';
const calendar = new Calendar(calendarEl, {
// ...other options
locale: frLocale, // Use French locale
// Or use multiple locales
locales: [frLocale, esLocale],
locale: 'fr' // Set the active locale
});
Business Hours
// Simple business hours (9am to 5pm, Monday to Friday)
businessHours: true
// Customized business hours
businessHours: {
daysOfWeek: [1, 2, 3, 4, 5], // Monday to Friday
startTime: '08:00', // 8am
endTime: '18:00' // 6pm
}
// Multiple business hour ranges
businessHours: [
{
daysOfWeek: [1, 2, 3, 4], // Monday to Thursday
startTime: '08:00',
endTime: '18:00'
},
{
daysOfWeek: [5], // Friday
startTime: '08:00',
endTime: '14:00' // 2pm (shorter day)
}
]
SmartAdmin Integration
For optimal integration with SmartAdmin, consider these tips:
Event Colors
Use SmartAdmin color variables for consistent styling:
// Use SmartAdmin color variables
events: [
{
title: 'Critical Task',
start: '2023-01-05',
backgroundColor: 'var(--danger-500)',
borderColor: 'var(--danger-500)'
},
{
title: 'Team Meeting',
start: '2023-01-07',
backgroundColor: 'var(--primary-500)',
borderColor: 'var(--primary-500)'
},
{
title: 'Completed Project',
start: '2023-01-09',
backgroundColor: 'var(--success-500)',
borderColor: 'var(--success-500)'
}
]
// Or use predefined SmartAdmin classes
events: [
{
title: 'Warning Event',
start: '2023-01-11',
classNames: ['bg-warning-500', 'text-white']
},
{
title: 'Info Event',
start: '2023-01-13',
classNames: ['bg-info-500', 'text-white']
}
]
Panel Integration
Use SmartAdmin panels for a consistent look:
<div class="row">
<div class="col-xl-12">
<div id="panel-1" class="panel">
<div class="panel-hdr">
<h2>
Company <span class="fw-300"><i>Calendar</i></span>
</h2>
<div class="panel-toolbar">
<button class="btn btn-panel" data-action="panel-collapse">
<svg class="sa-icon">
<use class="panel-collapsed-icon" href="img/sprite.svg#minus-circle"></use>
<use class="panel-expand-icon" href="img/sprite.svg#plus-circle"></use>
</svg>
</button>
<button class="btn btn-panel" data-action="panel-fullscreen">
<svg class="sa-icon">
<use href="img/sprite.svg#stop-circle"></use>
</svg>
</button>
</div>
</div>
<div class="panel-container show">
<div class="panel-content">
<div id="calendar"></div>
</div>
</div>
</div>
</div>
</div>
Modal Integration for Event Details
// Calendar setup with event click handling for modals
const calendar = new Calendar(calendarEl, {
// ...other options
eventClick: function(info) {
// Prevent default action (URL navigation)
info.jsEvent.preventDefault();
// Get event details
const event = info.event;
const title = event.title;
const start = event.start ? event.start.toLocaleString() : '';
const end = event.end ? event.end.toLocaleString() : '';
const description = event.extendedProps.description || '';
// Populate and show modal with Bootstrap 5
const modal = new bootstrap.Modal(document.getElementById('event-details-modal'));
document.getElementById('modal-event-title').textContent = title;
document.getElementById('modal-event-time').textContent = start + ' - ' + end;
document.getElementById('modal-event-description').textContent = description;
// Set up edit/delete buttons if needed
document.getElementById('edit-event-btn').onclick = function() {
// Open edit form for this event
openEditForm(event);
modal.hide();
};
document.getElementById('delete-event-btn').onclick = function() {
if (confirm('Are you sure you want to delete this event?')) {
event.remove();
// Also delete from backend
deleteEventFromServer(event.id);
modal.hide();
}
};
modal.show();
}
});
Troubleshooting
- Calendar not displaying? Ensure the container has a defined height.
- Events not appearing? Check the date range and time format of your events.
- Styling issues? Make sure
themeSystem: 'bootstrap'
is set. - Icons not showing? Verify the custom theme is properly loaded.
Calendar Height Issues
// Set explicit height
const calendar = new Calendar(calendarEl, {
// ...other options
height: 800 // Explicit pixel height
});
// Or use parent container's height
const calendar = new Calendar(calendarEl, {
// ...other options
height: 'parent' // Use parent container's height
});
// Or use CSS
#calendar {
height: 800px;
}
// For responsive height
#calendar {
height: calc(100vh - 250px); /* Viewport height minus offset */
}
AJAX Loading Issues
// Debug AJAX event loading
events: function(info, successCallback, failureCallback) {
console.log('Fetching events for', info.startStr, 'to', info.endStr);
fetch('/api/events?start=' + info.startStr + '&end=' + info.endStr)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log('Loaded events:', data);
successCallback(data);
})
.catch(error => {
console.error('Error loading events:', error);
failureCallback(error);
});
}
Further Resources
For more advanced usage and detailed API documentation, refer to these resources: