_docs-v4/upgrading-from-v3.md
Version 4 is the biggest FullCalendar release to date. It sheds a number of outdated dependencies and offers a more modern API. It is also the first time connector plugins to third-party libraries are offered.
Major breaking changes:
Calendar, EventSource, and Event classes.Major new features:
position:sticky when possible. Much more performant.Want the full docs in a non-changelog format? [View the docs]({{ site.baseurl }}/v4)
Found a bug? Report it on the issue tracker
Have a comment? Comment on the blog post
</div> <div class='sidebar-layout__sidebar sidebar-layout__sidebar--bordered' id='toc' markdown='1'> ## Table of ContentsPreviously, a calendar was initialized by calling the $().fullCalendar() jQuery method. FullCalendar resided in a single JavaScript file that needed to be included on the page before pageload.
Now, a calendar is initialized by instantiating a Calendar object and then calling its render method. Also, all functionality has been broken into plugins. You'll need to use the plugin system for any and all views in addition to drag-n-drop functionality. See a full list of plugins »
If you want to use script tags and browser globals you can do something like this:
<link href='fullcalendar/core/main.css' rel='stylesheet' />
<link href='fullcalendar/daygrid/main.css' rel='stylesheet' />
<script src='fullcalendar/core/main.js'></script>
<script src='fullcalendar/daygrid/main.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
plugins: [ 'dayGrid' ],
defaultView: 'dayGridMonth'
});
calendar.render();
});
</script>
Or if you want to use an ES6 build environment install the necessary dependencies:
npm install --save @fullcalendar/core @fullcalendar/daygrid
And then write your JS:
import { Calendar } from '@fullcalendar/core';
import dayGridPlugin from '@fullcalendar/daygrid';
document.addEventListener('DOMContentLoaded', function() {
var calendarEl = document.getElementById('calendar');
var calendar = new Calendar(calendarEl, {
plugins: [ dayGridPlugin ],
defaultView: 'dayGridMonth'
});
calendar.render();
});
You'll need to manually include the necessary CSS files on your page like so:
<link href='node_modules/@fullcalendar/core/main.css' rel='stylesheet' />
<link href='node_modules/@fullcalendar/daygrid/main.css' rel='stylesheet' />
Also, many of the views have been renamed:
The premium Scheduler product has been broken into a number of separate plugins. Also, the names and meanings of each view have changed.
Previously, to display a resource view, you would specify the resources option, and if working with vertical resource view, you might specify groupByResource or groupByDateAndResource as well. In v4, things are much more explicit. To display a resource view, you must choose one of the following views:
The following views previouly might have displayed resources, but in v4, they are guaranteed to NOT display resources:
calendar.next();
var calendar = new Calendar(calendarEl, {
select: function() {
console.log(this === calendar); // true
}
});
var optionValue = calendar.getOption('optionName');
And instead of using jQuery to set options like $().fullCalendar('option', 'optionName', 'optionValue'), use setOption:
calendar.setOption('optionName', 'optionValue');
New things:
<table> <tr> <th><a href='updateSize'>updateSize</a></th> <td markdown='1'> Will readjust a calendar's sizing (what the `render` method used to do). </td> </tr> <tr> <th><a href='Calendar-batchRendering'>batchRendering</a></th> <td markdown='1'> Will group operations and consolidate them into a single rerender. Solves [issue 3262](https://github.com/fullcalendar/fullcalendar/issues/3262) </td> </tr> <tr> <th><a href='rerenderDelay'>rerenderDelay</a></th> <td markdown='1'> The amount of milliseconds to wait before rerendering *anything* on a calendar. </td> </tr> </table>Breaking changes:
<table> <tr> <th>Moment JS removal</th> <td markdown='1'> Moment JS has been removed as a dependency and thus there is no need to include `moment(.min).js`. The API now deals in [native Date objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) as opposed to Moment objects. Related to [issue 3937](https://github.com/fullcalendar/fullcalendar/issues/3937), [3672](https://github.com/fullcalendar/fullcalendar/issues/3672), [3672](https://github.com/fullcalendar/fullcalendar/issues/3274). </td> </tr> <tr> <th>Ambiguously-timed Moments</th> <td markdown='1'> Will now be `Date` objects with a time of `00:00:00`. Callbacks nearly always provide an `allDay` boolean in addition. [Issue 2981](https://github.com/fullcalendar/fullcalendar/issues/2981) </td> </tr> <tr> <th><a href='date-formatting'>date formatting strings</a></th> <td markdown='1'> Instead of specifying date formats as command strings like `MMMM d, YYYY`, you specify them as objects like `{ month: 'long', day: 'numeric', year: 'numeric' }`. This technique leverages the native [DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat) which results in greater flexibility across locales and smaller locale files.Also, you can use functions to programmatically generate date string text. Issue 3664
You can still use command strings, but you'll need to use the moment or luxon plugins.
</td> </tr> <tr> <th><a href='formatRange'>formatRange method</a></th> <td markdown='1'> Signature has been changed from `formatRange( moment1, moment2, formatString [, separator, isRTL ] )` to `formatRange( date1, date2, settings )`. Both `date1` and `date2` are [Date object inputs](date-parsing) and `settings` accepts [formatting](date-formatting) keys and other stuff too. </td> </tr> <tr> <th><a href='duration'>duration objects</a></th> <td markdown='1'> Instead of Moment Duration objects, these objects are plain objects in the form `{ years, months, days, milliseconds }`.You can use the moment or luxon plugins to convert them to something more powerful.
</td> </tr> <tr> <th><a href='weekNumberCalculation'>weekNumberCalculation</a></th> <td markdown='1'> When specifying a function, the function will receive a single [Date object](date-object), not a Moment. </td> </tr> </table>New things:
<table> <tr> <th><a href='defaultRangeSeparator'>defaultRangeSeparator</a></th> <td markdown='1'> Determines the separator text used for [date-formatting](date-formatting) ranges throughout the API, except for the toolbar title text, which is affected by [titleRangeSeparator](titleRangeSeparator). </td> </tr> <tr> <th><a href='formatDate'>formatDate util func</a></th> <td markdown='1'> Formats a date into a string. </td> </tr> <tr> <th><a href='Calendar-formatDate'>formatDate method</a></th> <td markdown='1'> Formats a date into a string. Inherits the locale and time zone settings of the calendar it’s called on. </td> </tr> <tr> <th><a href='Calendar-formatIso'>formatIso method</a></th> <td markdown='1'> Formats a date into an ISO8601 string. Outputs a UTC offset appropriate to the calendar it’s called on. </td> </tr> <tr> <th><a href='Calendar-formatRange'>formatRange method</a></th> <td markdown='1'> Formats two dates, a start and an end, into a string. Inherits settings from the calendar it's called on. </td> </tr> </table>Breaking changes:
<table> <tr> <th>paths to locale files</th> <td markdown='1'> `locale/*.js` files have been moved to `locales/*.js` (added an `s`)locale-all.js files has been moved to locales-all.js (added an s)
isRTL: true becomes dir: 'rtl'
Enhancements:
If you need a locale that does not have a matching locales/*.js file you may still set the locale setting. You will get partial support: most date-related strings within the calendar will correctly translate, but those in the buttons of the header/footer will not.
Previously, event objects would be specified as plain objects, and then when accessing those same events in other parts of the API, they would be slightly-massaged versions of the same plain objects. Now, you still specify plain objects (though some properties have changed), but when you retrieve them in other parts of the API, they are instances of the Event class with methods for manipulation.
The plain-object's input properties have changed a bit:
<table> <tr> <th><del>_id</del></th> <td markdown='1'> `_id` can no longer be specified. </td> </tr> <tr> <th>id</th> <td markdown='1'> Was previously used to group related events together, so that they could be dragged/resized together. That is now done with `groupId`. The `id` properties should now be unique across all events in a calendar! </td> </tr> <tr> <th>recurring props (start/end/dow)</th> <td markdown='1'> These props were never officially supported. Use `startTime`, `endTime`, and `daysOfWeek` instead. See [simple event recurrence](recurring-events). </td> </tr> </table>The outputted object, which is now an instance if the Event class, has properties that differ from the previously-available massaged plain-object:
It is also possible to specify an explicit extendedProps hash in the plain object. Issue 3228
Various methods of the Calendar object that manipulate events have been converted to Event methods:
var someEvents = calendar.getEvents().filter(function(event) {
return event.title === 'My Event';
});
var event = calendar.getEventById('a');
event.setProp('title', 'new title');
Manipulation methods: setProp, setExtendedProp, setStart, setEnd, setDates, setAllDay, moveStart, moveEnd, moveDates
</td> </tr> <tr> <th><del>removeEvent</del></th> <td markdown='1'> Removed. Instead, retrieve an [Event object](event-object) and then call its [remove method](Event-remove):var event = calendar.getEventById('a');
event.remove();
The following settings have changed:
<table> <tr> <th><a href='defaultTimedEventDuration'>defaultTimedEventDuration</a></th> <td markdown='1'> The default has changed from 2 hours to 1 hour. </td> </tr> </table>Also, recurring events is now a built-in feature! You can use simple event recurrence or use the RRule adapater. Issue 387
Just as before, event sources can be specified in their "extended form", a plain object with properties. The format for this plain object has changed slightly:
<table> <tr> <th>overlap</th> <td markdown='1'> Can longer specify a function. Use the calendar-wide [eventOverlap](eventOverlap) instead. </td> </tr> <tr> <th>allow (new)</th> <td markdown='1'> Like the calendar-wide [eventAllow](eventAllow) but for this event source only. </td> </tr> <tr> <th>success (new)</th> <td markdown='1'> A function that gets called when fetching succeeds. Will receive two arguments, the raw event array and an [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) if applicable. Can massage the response by returning an event source array to use instead. </td> </tr> <tr> <th>failure (new)</th> <td markdown='1'> A function that gets called when fetching failed. Probably because [an AJAX request](events-json-feed) failed. Receives one argument, an error object. </td> </tr> <tr> <th>eventDataTransform</th> <td markdown='1'> Can now return `false` to exclude an event from being included. The calendar-wide [eventDataTransform](eventDataTransform) can do this too. </td> </tr> </table>This plain object is then parsed and becomes available in places like getEventSourceById and the event object's source property. Previously, these event source references would be slighly massaged version of the original plain object. Now, they are instances of the EventSource class and have methods that allow manipulation.
In v4, this new EventSource object is rather limited, offering only two properties: id and url. More info
Also, the EventSource object offers methods that replace the following Calendar methods:
var eventSource = calendar.getEventSourceById('a');
eventSource.refetch();
var eventSource = calendar.getEventSourceById('a');
eventSource.remove();
There are two new calendar-wide callbacks:
<table> <tr> <th><a href='eventSourceSuccess'>eventSourceSuccess</a></th> <td markdown='1'> A function that gets called when fetching succeeds. Will receive two arguments, the raw event array and an [XHR](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) if applicable. Can massage the response by returning an event source array to use instead. [Issue 2431](https://github.com/fullcalendar/fullcalendar/issues/2431) </td> </tr> <tr> <th><a href='eventSourceFailure'>eventSourceFailure</a></th> <td markdown='1'> A function that gets called when fetching failed. Probably because [an AJAX request](events-json-feed) failed. Receives one argument, an error object. </td> </tr> </table>An event-fetching function previously accepted the following arguments:
function( startMoment, endMoment, timeZoneStr, callback )
Now, it accepts the following arguments:
function( fetchInfo, successCallback, failureCallback )
It must call successCallback, failureCallback, or return a Promise. fetchInfo is an object that has a bunch of other properties. See the full article. A stubbed example of how to use the new signature:
var calendar = new Calendar(calendarEl, {
events: function(fetchInfo, successCallback, failureCallback) {
console.log(fetchInfo.startStr); // '2018-08-26T00:00:00-05:00'
console.log(fetchInfo.endStr); // '2018-10-07T00:00:00-05:00'
console.log(fetchInfo.timeZone); // 'local'
successCallback([]);
}
})
Solves issue 3593
The following FullCalendar functionality has been affected:
<table> <tr> <th>JSONP requesting</th> <td markdown='1'> It is no longer possible to request events via JSONP. CORS will be used instead. Make sure your server is set up to do CORS. </td> </tr> <tr> <th>jQuery.ajax settings</th> <td markdown='1'> The full range of [jQuery.ajax](https://api.jquery.com/jquery.ajax/) settings are **no longer accepted**. However, can use the following new settings:method - something like 'GET' (the default) or 'POST'extraParams - will send GET/POST data to the server. the data property was previously usedsuccess - Will receive two arguments, the raw event array and an XHRfailure - Receives one argument, an error objectvar calendar = new Calendar(calendarEl, {
events: {
url: '/myfeed.php',
extraParams: function() {
return {
cachebuster: new Date().valueOf()
};
}
}
});
The following request parameters have been affected:
<table> <tr> <th><a href='startParam'>startParam</a></th> <td markdown='1'> Would previously generate strings like `2019-09-01` which did not have time parts or UTC offsets. Now, the string is guaranteed to have a time part (most likely `00:00:00`) and will have a UTC offset that is dependant on the current [timeZone](timeZone). If the timeZone is set to `'local'` and the user is localed in New York, the string might be `2019-09-01T00:00:00-05:00`. [Issue 3593](https://github.com/fullcalendar/fullcalendar/issues/3593) </td> </tr> <tr> <th><a href='startParam'>endParam</a></th> <td markdown='1'> Same comments as `startParam` </td> </tr> <tr> <th><del>timezoneParam</del></th> <td markdown='1'> Renamed to [timeZoneParam](timeZoneParam). Defaults to `"timeZone"` instead of `"timezone"`.If your server-side scripts previously relied on a timezone= GET/POST parameter, change it to timeZone instead!
The Google Calendar Event Source has been affected:
<table> <tr> <th><del>googleCalendarError</del></th> <td markdown='1'> Removed. Use [eventSourceFailure](eventSourceFailure) instead. [Issue 3982](https://github.com/fullcalendar/fullcalendar/issues/3982) </td> </tr> <tr> <th>timeZone</th> <td markdown='1'> Previously, it was possible to specify timeZones with spaces such as "America/New York". Now, you must use underscores like "America/New_York". </td> </tr> </table>The way Views are customized and defined has been affected:
<table> <tr> <th><a href='view-specific-options'>view-specific options</a></th> <td markdown='1'> In parity with how view names have been renamed, instead of specifying `agenda` and `basic` to affect views of a certain type, use `timeGrid` and `dayGrid` respectively. </td> </tr> <tr> <th><a href='custom-view-with-js'>custom views written in JS</a></th> <td markdown='1'> When subclassing the `View` class, the methods that must be implemented have changed quite a bit. [More info](custom-view-with-js). </td> </tr> <tr> <th>registering a custom view</th> <td markdown='1'> Previously, to globally define a new type of view, you would use this technique:$.fullCalendar.views.specialView = {
type: 'theViewType',
defaults: { slotLabalInterval: '06:00' }
};
$.fullCalendar.views.customView = {
'class': CustomViewClass
};
This must rewritten as a plugin:
import { createPlugin } from '@fullcalendar/core';
export default createPlugin({
views: {
specialView: {
type: 'theViewType',
slotLabalInterval: '06:00' // top-level property!
},
customView: CustomViewClass // can pass-in the class directly!
}
})
Solves issue 3657.
</td> </tr> </table>The View object's properties have changed a bit:
<table> <tr> <th><del>name</del></th> <td markdown='1'> Renamed to `type` </td> </tr> <tr> <th> <del>intervalStart</del> / <del>intervalEnd</del> </th> <td markdown='1'> Renamed to `currentStart` / `currentEnd`. The current month/week/day/etc. </td> </tr> <tr> <th> <del>start</del> / <del>end</del> </th> <td markdown='1'> Renamed to `activeStart` / `activeEnd`. The date range that can be selected and accept events. </td> </tr> </table>The following view-rendering-related callbacks have been affected:
<table> <tr> <th><del>viewRender</del></th> <td markdown='1'> Renamed to [datesRender](datesRender). Parameters have changed. </td> </tr> <tr> <th><del>viewDestroy</del></th> <td markdown='1'> Renamed to [datesDestroy](datesDestroy). Parameters have changed. </td> </tr> <tr> <th><a href='viewSkeletonRender'>viewSkeletonRender</a> (new)</th> <td markdown='1'> Triggered after a view’s non-date-related DOM structure has been rendered. </td> </tr> <tr> <th><a href='viewSkeletonDestroy'>viewSkeletonDestroy</a> (new)</th> <td markdown='1'> Triggered before a view’s DOM skeleton is removed from the DOM. </td> </tr> </table>The following settings have been affected:
<table> <tr> <th><a href='columnHeaderFormat'>columnHeaderFormat</a></th> <td markdown='1'> No longer accepts a format-string out of the box. [Use a date-formatting object instead](date-formatting). </td> </tr> <tr> <th><del>columnFormat</del></th> <td markdown='1'> This deprecated alias of [columnHeaderFormat](columnHeaderFormat) has been removed. Use [columnHeaderFormat](columnHeaderFormat) instead. </td> </tr> <tr> <th><a href='slotLabelFormat'>slotLabelFormat</a></th> <td markdown='1'> No longer accepts a format-string out of the box. [Use a date-formatting object instead](date-formatting). </td> </tr> <tr> <th><a href='columnHeaderText'>columnHeaderText</a></th> <td markdown='1'> Accepts a normal [Date object](date-object) now. </td> </tr> <tr> <th><a href='dayRender'>dayRender</a></th> <td markdown='1'> Instead of receiving `( date, el )`, it now accepts an object. Stub example:var calendar = new Calendar(calendarEl, {
dayRender: function(info) {
console.log(info.date.toISOString());
console.log(info.el);
console.log(info.view.type);
}
});
The getDate method will return a Date object not a Moment.
The interaction plugin is now required to detect date clicking and selecting:
import { Calendar } from '@fullcalendar/core';
import interactionPlugin from '@fullcalendar/interaction';
let calendar = new Calendar(calendarEl, {
plugins: [ interactionPlugin ],
selectable: true,
select: function(info) { },
dateClick: function(info) { }
});
Other breaking changes:
<table> <tr> <th><del>dayClick</del></th> <td markdown='1'> Renamed to [dateClick](dateClick). Instead of ordered arguments, receives on object argument. Stub example:var calendar = new Calendar(calendarEl, {
dateClick: function(info) {
console.log(info.date.toISOString());
console.log(info.dateStr);
console.log(info.allDay);
console.log(info.dayEl);
console.log(info.jsEvent);
}
});
info.date is a Date object, not a Moment.
Also, this is now triggered when the user clicks on top of a background event. Issue 2843
</td> </tr> <tr> <th><a href='select-callback'>select callback</a></th> <td markdown='1'> Instead of ordered arguments, receives on object argument. Stub example:var calendar = new Calendar(calendarEl, {
select: function(info) {
console.log(info.start.toISOString());
console.log(info.end.toISOString());
console.log(info.startStr + ' - ' + info.endStr);
console.log(info.allDay);
}
});
info.start and info.end are Date objects, not Moments.
Also, a bug related to an unwanted unselect on touch devices has been fixed. Issue 4062
The following settings have been affected:
<table> <tr> <th><a href='nextDayThreshold'>nextDayThreshold</a></th> <td markdown='1'> Default has been changed to `00:00:00`. The previous default of `09:00:00` didn't make a lot of sense. [Issue 2902](https://github.com/fullcalendar/fullcalendar/issues/2902)Also, a bug with events that begin before the view's start date has been fixed. Issue 3943
</td> </tr> <tr> <th><a href='eventOrder'>eventOrder</a></th> <td markdown='1'> This value how has complete control over ordering events within a day, as opposed to before when events were always ordered by time first. The default is now `'start,-duration,allDay,title'`. [Issue 2907](https://github.com/fullcalendar/fullcalendar/issues/2907)If your old value for this setting was something like '-duration,title', you'll want to include the start time in the value now. So, convert it to 'start,-duration,title'.
var calendar = new Calendar(calendarEl, {
eventRender: function(info) {
console.log(info.event.title);
console.log(info.el);
console.log(info.view);
console.log(info.isStart);
console.log(info.isEnd);
console.log(info.isMirror);
}
});
Addresses issue 3674, 3956, 2616, 3952, and 3311
</td> </tr> <tr> <th><a href='eventDestroy'>eventDestroy</a></th> <td markdown='1'> Instead of accepting `( event, el, view )`, it now accepts an object. Stub example:var calendar = new Calendar(calendarEl, {
eventDestroy: function(info) {
console.log(info.event.title);
console.log(info.el);
console.log(info.view);
}
});
The following Calendar methods have been affected:
Visual changes:
In a timeGrid view (previously called "<del>agenda view</del>", when an event is all-day, it would previously only render in the all-day area at the top. Now, it will render in both the all-day area and the time slots. See this illustration.
The following callbacks have been affected:
<table> <tr> <th><a href='eventClick'>eventClick</a></th> <td markdown='1'> Where previously received ordered arguments `( event, jsEvent, view )`, will now receive a single object argument `{ event, el, jsEvent, view }`. Now fires for background events. [Issue 2808](https://github.com/fullcalendar/fullcalendar/issues/2808)You can no longer return false to cancel the browser's navigation to the Event object's URL. Instead, use the jsEvent:
var calendar = new Calendar(calendarEl, {
eventClick: function(info) {
info.jsEvent.preventDefault();
}
});
The interaction plugin is now required to do event drag-n-drop and resizing:
import { Calendar } from '@fullcalendar/core';
import interactionPlugin from '@fullcalendar/interaction';
let calendar = new Calendar(calendarEl, {
plugins: [ interactionPlugin ],
editable: true
});
Other breaking changes:
<table> <tr> <th><a href='eventDragStart'>eventDragStart</a></th> <td markdown='1'> Where previously received ordered arguments `( event, jsEvent, ui, view )`, now receives a single object `{ event, jsEvent, view }`. </td> </tr> <tr> <th><a href='eventDragStop'>eventDragStop</a></th> <td markdown='1'> Where previously received ordered arguments `( event, jsEvent, ui, view )`, now receives a single object `{ event, jsEvent, view }`. </td> </tr> <tr> <th><a href='eventDrop'>eventDrop</a></th> <td markdown='1'> Previously accepted ordered arguments `( event, delta, revertFunc, jsEvent, ui, view )`. Now accepts an object:var calendar = new Calendar(calendarEl, {
eventDrop: function(info) {
console.log(info.event);
console.log(info.oldEvent); // data before the drop
console.log(info.delta); // how far it was moved
console.log(info.jsEvent);
console.log(info.newResource); // if using a resource view
console.log(info.oldResource); // if using a resource view
if (confirm('revert change?')) {
info.revert();
}
}
})
The delta property is a Duration object, no longer a Moment Duration. The oldEvent property is a new feature that allows you to inspect the event's values prior to the mutation.
var calendar = new Calendar(calendarEl, {
eventResize: function(info) {
console.log(info.event);
console.log(info.prevEvent); // data before the drop
console.log(info.startDelta); // how far start was moved
console.log(info.endDelta); // how far end was moved
console.log(info.jsEvent);
if (confirm('revert change?')) {
info.revert();
}
}
})
The startDelta is for resizing from start edge (with eventResizableFromStart). endDelta is for resizing from ending edge. Both are Duration objects, no longer Moment Durations. The prevEvent property is a new feature that allows you to inspect the event's values prior to the mutation. Issue 4148
.fc-event.fc-dragging:not(.fc-selected) {
opacity: .75;
}
You can tweak this CSS to get different opacity values for different scenarios.
</td> </tr> <tr> <th markdown='1'> [eventConstraint](eventConstraint)EventSource::constraint
Event::constraint
</th> <td markdown='1'> Can no longer specify a single string event ID, but rather a single string `groupId` that will match [Event objects](event-object).The recurring properties dow/start/end have been renamed to daysOfWeek/startTime/endTime.
Can accept an array of objects. Useful if you want to specify multiple date ranges.
</td> </tr> </table>Version 4 offers the following new features:
<table> <tr> <th>no third-party dependencies</th> <td markdown='1'> You no longer need jQuery UI to be able to drag elements into a calendar. You can use the built-in `Draggable` API. [More information](external-dragging). [Issue 3902](https://github.com/fullcalendar/fullcalendar/issues/3902) </td> </tr> <tr> <th>plugins</th> <td markdown='1'> If you'd like to use a third-party library for dragging such as [Dragula](https://github.com/bevacqua/dragula), you can use the `ThirdPartyDraggable` API. [More information](third-party-dragging). Will work for any other third party library. </td> </tr> <tr> <th>dragging between calendars</th> <td markdown='1'> It's possible to drag events between two separate Calendar instances. [More information](other-calendar-dragging). [Issue 820](https://github.com/fullcalendar/fullcalendar/issues/820) </td> </tr> </table>The following existing functionality has been affected:
<table> <tr> <th markdown='1'>`data-event-*` attributes</th> <td markdown='1'> When [associating event data with an element](external-dragging#associating-event-data), you can no longer specify properties as separate HTML attributes. Instead, bundle them all together under one JSON string in the `data-event` attribute. Or better yet, just use the `Draggable` JS API. </td> </tr> <tr> <th markdown='1'>`data-event="1"` attribute</th> <td markdown='1'> You would previously specify a `data-event="1"` HTML attribute if you wanted to create an event upon drop, but did not have any other event-creation data to specify. This is now unnecessary because event creation happens by default. </td> </tr> <tr> <th markdown='1'><del>start</del> and <del>time</del> properties</th> <td markdown='1'> External events that are dropped on all-day areas can be given a default time. This was previously done with the `time`/`start` properties. The proprty has been rename to `startTime` to be more consistent with naming elsewhere in the API. See [External Event Dragging](external-dragging) for more info. </td> </tr> <tr> <th>event creation and <a href='eventReceive'>eventReceive callback</a></th> <td markdown='1'> Event creation upon drop and firing of the [eventReceive](eventReceive) callback will happen by default. To prevent this from happening, specify `{ create: false }` in your event data. [More information](external-dragging#other-draggable-settings).The eventReceive callback previously received a single Event object argument. It now receives an object { event, draggedEl, view }. Also, it will now also be called when an event from another calendar has been dropped.
If dropped on an all-day slot, the date property will always have a 00:00:00 time, regardless of the startTime in the event data, whereas previously the startTime would have been added.
The following settings related to the event popover have been affected:
<table> <tr> <th><a href='dayPopoverFormat'>dayPopoverFormat</a></th> <td markdown='1'> Does not accept date-formatting string by default. Use a [date-formatting object](date-formatting). </td> </tr> <tr> <th><a href='navLinkDayClick'>navLinkDayClick</a></th> <td markdown='1'> When specifying a function, accepts a [Date object](date-object) not a Moment. </td> </tr> </table>When specifying business hours, the recurring properties dow / start / end have been renamed to daysOfWeek / startTime / endTime.
The following settings related to toolbars (aka, the header and footer) have been affected:
<table> <tr> <th><a href='titleFormat'>titleFormat</a></th> <td markdown='1'> Does not accept date-formatting string by default. Use a [date-formatting object](date-formatting). </td> </tr> <tr> <th><a href='titleRangeSeparator'>titleRangeSeparator</a> (new)</th> <td markdown='1'> Determines the separator text when formatting the date range in the toolbar title. Default to an elongated dash. </td> </tr> </table>The MonthView class is no longer exposed. Internally, the functionality has been rolled into DayGridView, which is exposed.
As mentioned above, the "<del>agenda views</del>" have been renamed to the timeGrid views. The following settings have been affected:
The following settings related to List View have been affected:
<table> <tr> <th><a href='listDayFormat'>listDayFormat</a></th> <td markdown='1'> Does not accept date-formatting string by default. Use a [date-formatting object](date-formatting). </td> </tr> <tr> <th><a href='listDayAltFormat'>listDayAltFormat</a></th> <td markdown='1'> Does not accept date-formatting string by default. Use a [date-formatting object](date-formatting). </td> </tr> </table>Breaking changes:
<table> <tr> <th><a href='resourceColumns'>resourceColumns</a></th> <td markdown='1'> The `render` function's first argument is **always** a [Resource object](resource-object). Previously, it would vary depending on whether there was a `field` specified or not. </td> </tr> <tr> <th>User-resizable columns and resource-area</th> <td markdown='1'> The user is able to resize the [resourceAreaWidth](resourceAreaWidth) as well as the columns created by [resourceColumns](resourceColumns). Previously it "just worked," but <strong>now you'll need to load the [interaction plugin](editable#required-plugin)</strong>. </td> </tr> </table>Previously, the <del>groupByResource</del> and <del>groupByDateAndResource</del> settings would do two things. They would "activate" a vertical resource view (as opposed to rendering the non-resource version of the view) as well as control the headers at the top of the view.
Now, explicitly specifying a resource view such as resourceTimeGridDay is how you "activate" a vertical resource. Additionally, these two settings have been collapsed into one:
datesAboveResources: false // the default. instead of groupByResource:true
datesAboveResources: true // instead of groupByDateAndResource:true
A resource-fetching function previously accepted the following arguments:
function( callback, startMoment, endMoment, timeZone )
Now, it acceps the following arguments:
function( fetchInfo, successCallback, failureCallback )
It must call successCallback, failureCallback, or return a Promise. fetchInfo is an object that contains the date-related properties. See the full article.
Other resource-fetching changes:
The following Calendar triggers have been affected:
Previously, resource objects would be specified as plain objects, and then when accessing those same events in other parts of the API, they would be slightly-massaged versions of the same plain objects. Now, you still specify plain objects, but when you retrieve them in other parts of the API, they are instances of the Resource class with methods for manipulation.
The following properties are now accepted in the raw object:
<table> <tr> <th>eventOverlap</th> <td> The <a href='eventOverlap'>eventOverlap</a> setting for associated events. Does not accept a function. </td> </tr> <tr> <th>eventConstraint</th> <td> The <a href='eventConstraint'>eventConstraint</a> setting for associated events. </td> </tr> <tr> <th>eventAllow</th> <td> The <a href='eventAllow'>eventAllow</a> setting for associated events. </td> </tr> </table>The plain object will eventually be parsed into a proper Resource object, which has a number of differences from v3:
<table> <tr> <th markdown='1'><del>parent</del></th> <td markdown='1'> Removed. Use [getParent](Resource-getParent) instead. </td> </tr> <tr> <th markdown='1'><del>children</del></th> <td markdown='1'> Removed. Use [getChildren](Resource-getChildren) instead. </td> </tr> <tr> <th markdown='1'>`extendedProps`</th> <td markdown='1'> Where all non-standard properties are stored. Previously, non-standard properties would be stored in the top-level object. </td> </tr> </table>The following resource-related methods/properties in the Calendar object have been affected:
There is currently no way to retrieve the element(s) that were previously available in bodyTds. Issue 481
Previously, the Core package was at version 3.x.x and the Scheduler package was at 1.x.x. There was no rhyme or reason as to which versions were compatible.
Now, all of v4's plugins will be at 4.x.x including Scheduler functionality. All plugins with the same minor version (like 4.1.x) are implied to be compatible.
Support for NPM (and Yarn) is strong, but here's what happened to support for other package managers:
<table> <tr> <th>Bower</th> <td markdown='1'> Support has been dropped. </td> </tr> <tr> <th>Composer</th> <td markdown='1'> Support has been dropped. [More info](https://github.com/fullcalendar/fullcalendar/issues/4489). </td> </tr> </table>