Upgrade guides for Scheduler Pro v4.0.0+
Scheduler Pro v4.0.0
Be sure to also check out the news in Grid and Scheduler.
Version in line with other Bryntum products
The version of Scheduler Pro was bumped from 1.0 -> 4.0 to bring it in line with Grid, Scheduler, Gantt and Calendar. This will make it easier to determine which versions are compatible with each other.
Dropped support for Edge 18 and older
We are not actively removing the fixes we have in place yet, but moving forward we will no longer add new fixes for versions of Edge <= 18. If you are using an old version of Edge, we strongly encourage you to update to a new blink based version.
Existing fixes are planned to be removed in version 5.0.
Async data manipulation changes
To simplify async data manipulation a bit, we have added two new functions that performs the engine commit internally, addAsync() and loadDataAsync(). Example of their usage, loadDataAsync() as an alternative to store.data = ... first:
await eventStore.loadDataAsync([my_dataset]);
// calculations are done, data is ready for further processing
And addAsync() would be used like this:
await eventStore.addAsync({ startDate : '2020-09-10', endDate : '2020-09-14' });
// duration is calculated and available
Changed event triggering timing
The stores that are part of the project (EventStore, ResourceStore, AssignmentStore and DependencyStore) has had the timing of their event triggering for certain events modified. The change was made to assure async date calculations are finished when the event is triggered. This affects the following events:
addremoveremoveAllchangerefresh
This change should lead to better backward compatibility with the old Scheduler. Consider the following scenario:
const scheduler = new SchedulerPro({
events : [/*...*/],
listeners : {
add({ records }) {
console.assert(records[0].endDate)
}
}
});
scheduler.eventStore.add({ startDate : '2020-09-09', duration : 1 });
Without the change, the add event would be triggered immediately on the call to add(). Since date calculations are now async (as described in section "Async date manipulation" above), the endDate would not yet be available.
With the change, the event is triggered after calculations has finished, making endDate available in the listener.
It is still possible to catch the events at the earlier stage, in case you do not care about waiting for data to be in a calculated state. To achieve that, listen for addBeforeCommit, removeBeforeCommit and so on instead.
WidgetHelper and BryntumWidgetAdapter
Registration of Widget classes for subsequent resolution through the type property of config objects has been simplified. The "Adapter" concept has been removed. Widget classes now register themselves with the Widget base class which is where they can also be looked up. When creating a custom widget, implement the static get type property to return the type name. And at the end simply call MyWidgetClass.initClass() to have the new Widget class register itself.
Old code:
class MyWidget extends Widget {
}
BryntumWidgetAdapterRegister.register('mywidget', MyWidget);
New code:
class MyWidget extends Widget {
static get type() {
return 'mywidget';
}
}
MyWidget.initClass();
Fewer widgets are auto imported with the removal of the Adapter which imported a base set of Widgets. This means that when not using a bundle, application code must import the widgets it uses. It also means that custom builds may be smaller by including only what is used.
If your code previously had:
import 'lib/Core/adapter/widget/BryntumWidgetAdapter.js';
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';
WidgetHelper.append([
{
type : 'button',
text : 'Click'
}
], /*...*/);
It should now instead not import the adapter, and instead directly import the button:
import WidgetHelper from 'lib/Core/helper/WidgetHelper.js';
import 'lib/Core/widget/Button.js';
WidgetHelper.append([
{
type : 'button',
text : 'Click'
}
], /*...*/);
Recurring Events
The method by which occurrences of recurring events are collected for rendering has changed.
Prior to 4.0.0, after any EventStore or EventModel mutation (load, filter, record change etc), the EventStore was scanned for instances of events with a recurrenceRule. For each one found, a sequence of occurrences which fell within the Scheduler's current TimeAxis date range was generated and these were inserted into the EventStore.
This could result in difficulty in managing the store content since "ephemeral" occurrences were mixed in with concrete event definitions and EventStoreadd events would be fired for these ephemeral occurrences which apps had to have code to ignore.
From 4.0.0, there is no RecurringEvents Feature. There is an enableRecurringEvents boolean config on the Scheduler instead. Occurrences of recurring events are provided on a "just in time" basis by a new EventStore API which must now be used when interrogating an EventStore.
EventStore.getEvents is a multipurpose event gathering method which can be asked to return events which match a set of criteria including a date range and a resource. By default, if the requested date range contains occurrences of a recurring event, those occurrences are returned in the result array.
myEventStore.getEvents({
resourceRecord : myResourceRecord,
startDate : myScheduler.timeAxis.startDate,
endDate : myScheduler.timeAxis.endDate
});
Occurrences are not present in the store's data collection.
To directly access occurrences of a recurring event which intersect a date range, use:
recurringEvent.getOccurrencesForDateRange(startDate, endDate);
The endDate argument is optional if the occurrence for one date is required. This method always returns an array. Note that it may be empty if no occurrences intersect the date range.
Convert an occurrence to an exception
To programmatically convert an occurrence to be a single exception to its owner's sequence use:
myOccurrence.beginBatch();
myOccurrence.startDate = DateHelper.add(myOccurrence.startDate, 1, 'day');
myOccurrence.name = 'Postponed to next day';
myOccurrence.recurrence = null; // This means it does NOT become a new recurring base event.
myOccurrence.endBatch();
Or as a single call to set():
myOccurrence.set({
startDate : DateHelper.add(myOccurrence.startDate, 1, 'day'),
name : 'Postponed to next day',
recurrence : null // This means it does NOT become a new recurring base event.
});
That will cause that event to be inserted into the store as a concrete event definition, firing an add event as would be expected, and will add an exceptionDate to its owning recurring event.
When syncing this change back to the server, the exceptionDates array for the modified recurring event now contains the exception dates correctly serialized into string form using the dateFormat of the EventModel. The system-supplied default value for this is 'YYYY-MM-DDTHH:mm:ssZ'
Convert an occurrence to a new recurring event sequence
To programmatically convert an occurrence to be the start of a new recurring sequence, use:
myOccurrence.beginBatch();
myOccurrence.startDate = DateHelper.set(myOccurrence.startDate, 'hour', 14);
myOccurrence.name = 'Moved to 2pm from here on';
myOccurrence.endBatch();
That will cause that event to be inserted into the store as a concrete recurring event definition, firing an add event as would be expected, and will terminate the previous recurring owner of that occurrence on the day before the new event.
TaskEditor configs changes
tabsConfig and extraItems configs are deprecated and will be removed in version 5.0. TaskEditor tabs and widgets in the tabs are configured in a single items config.
Old code:
const scheduler = new SchedulerPro({
features : {
taskEdit : {
editorConfig : {
extraItems : {
generaltab : [
{ type : 'button', text : 'New Button' }
]
}
},
tabsConfig : {
generaltab : { title : 'Common' },
notestab : false,
filestab : { type : 'custom_filestab' }
}
}
}
});
New code:
const scheduler = new SchedulerPro({
features : {
taskEdit : {
items : {
generalTab : {
title : 'Common',
items : {
newButton : { type : 'button', text : 'New Button' }
}
},
notesTab : false,
filesTab : { type : 'custom_filestab' }
}
}
}
});
Model Field Inheritance
Fields defined in a derived class Model that coincide by name with a field declared in a super class will now only override those field config properties specified by the derived class. This allows derived classes to adjust a field definition in one way, say to change the default value and still inherit other field properties, such as a convert function.
For example:
class ModelOne extends Model {
static get fields() {
return [
{ name : 'barcode', convert : v => String(v) }
];
}
}
class ModelTwo extends ModelOne {
static get fields() {
return [
{ name : 'barcode', defaultValue : 'ABC123' }
];
}
}
In previous releases, ModelTwo would have had to redefine the convert config for the barcode field.
Renamed CSS themes
The Default, Light and Dark themes were renamed to Classic, Classic-Light and Classic-Dark. This change highlights the fact that they are variations of the same theme, and that it is not the default theme (Stockholm is our default theme since Grid version 2.0).
If you are using one of these themes, you will have to adjust your css import to match the new name.
Old code:
<link rel="stylesheet" href="build/grid.dark.css" id="bryntum-theme">
New code:
<link rel="stylesheet" href="build/grid.classic-dark.css" id="bryntum-theme">
If you have theme specific selectors in your code/CSS you have to adjust those also:
Old code:
.b-theme-dark {
/*...*/
}
New code:
.b-theme-classic-dark {
/*...*/
}
SchedulerPro v4.0.4
Deprecated showDeleteButton on TaskEdit feature
The showDeleteButton config on the TaskEdit feature was deprecated in favor of the items config. It will be removed in 5.0. If you use it, the following snippets shows how to update your code:
Old code:
const scheduler = new SchedulerPro({
features : {
taskEdit : {
showDeleteButton : false
}
}
});
New code:
const scheduler = new SchedulerPro({
features : {
taskEdit : {
editorConfig : {
bbar : {
items : {
deleteButton : false
}
}
}
}
}
});
Scheduler Pro v4.0.8
Added short responses support to Crud Manager
Crud Manager default behaviour has been changed to allow short sync responses that include only server-side changes. Previously it was mandatory to mention all updated and removed records in the response to confirm the changes are applied. With this release the Crud Manager automatically confirms changes of all updated/removed records mentioned in the corresponding sync request. If your code relies on the old behavior please use supportShortSyncResponse to enable it back. To revert to the old behavior please set supportShortSyncResponse config to false:
new SchedulerPro({
/*...*/
project : {
// disable simlified responses support
supportShortSyncResponse : false,
/*...*/
}
});
CSS encoding
Bryntum now uses Dart SASS to compile CSS from SCSS for the themes. It outputs CSS encoded with UTF-8. The encoding is specified at the top of the CSS file as a @charset tag:
@charset "UTF-8";
It is important that this tag is preserved in the CSS used on page, to guarantee that font icons render as intended.
Minified CSS instead uses a byte order mark to specify encoding, which although invisible to the eye should be preserved in the file used on page.
If you use a custom build process that includes our CSS and icons are not rendered correctly in all browsers, the issue is most likely caused by missing encoding info. Try adding it back or serving the CSS with correct encoding specified in the HTTP header.
DependencyCreation events
DependencyCreation events were all missing useful params about the state of the creation state as you drag and drop to setup a link between two events. The data param is now deprecated and will be removed in a future major version.
Old code:
scheduler.on({
beforedependencycreatedrag({ data }) {
// Use undocumented params in data
}
});
New code:
scheduler.on({
dependencycreatedrop({ source, target, dependency }) {
// Documented access to source task, target task, and the created dependency
}
});
Frameworks examples
Frameworks examples were moved to examples/frameworks folder:
| Framework | Examples folder |
|---|---|
| Angular | examples/frameworks/angular |
| React | examples/frameworks/react |
| Vue v2 | examples/frameworks/vue |
| Vue v3 | examples/frameworks/vue-3 |
Scheduler frameworks examples were moved to examples-scheduler/frameworks folder:
| Framework | Examples folder |
|---|---|
| Angular | examples-scheduler/frameworks/angular |
| Ionic | examples-scheduler/frameworks/ionic |
| React | examples-scheduler/frameworks/react |
| Vue v2 | examples-scheduler/frameworks/vue |
| Vue v3 | examples-scheduler/frameworks/vue-3 |
Scheduler Pro v4.1.1
Wrapper dependencies
In order to support installing trial package alias for wrappers they now require adding @bryntum/schedulerpro dependency to application's package.json file.
Example for licensed version for Angular framework:
{
"dependencies": {
"@bryntum/schedulerpro": "4.1.1",
"@bryntum/schedulerpro-angular": "4.1.1"
}
}
Example for trial version for Angular framework:
{
"dependencies": {
"@bryntum/schedulerpro": "npm:@bryntum/schedulerpro-trial@4.1.1",
"@bryntum/schedulerpro-angular": "4.1.1"
}
}
Scheduler Pro v4.1.5
beforeTaskEditShow listeners can now be used to change/apply initial values
This release has changes to the beforeTaskEditShow event that might affect the logic of your app:
- It is now possible to assign values to task editor fields using a
beforeTaskEditShowlistener. - Values that are programmatically applied to the fields using
beforeTaskEditShowand later will now be applied to the task record (previously only user-typed changes were applied). - If a field is added to a task editor in a
beforeTaskEditShowlistener, make sure to apply an initial value for it since default values are applied at an earlier stage.
Scheduler Pro v4.2.0
EventDragCreate
The EventDragCreate feature now operates on a live instance of a new EventModel which is in the EventStore on a provisional basis until either confirmed or cancelled by the EventEdit UI.
The end times are manipulated live, and the UI performs appropriate updates. This is in contrast to having a proxy element dragged in place where an event may be placed if inserted.
If you have your own implementation of an event editor/task editor that is shown when drag create ends, this change might affect its behaviour. If you need to know if the event being edited is the result of a drag create operation (or a double click on the timeline), you can inspect the new isCreating flag of the event/task record.
Dependencies can now be created by dropping anywhere on the event bar element
In previous versions you had to hit a specific side circle element to define it. The new behavior allows you to setup a dependency by dropping anywhere on the task bar. This creates a dependency with the default type, as defined by the defaultValue of the DependencyModel type field.
If you prefer the old behavior, simply set allowDropOnEventBar to false on the feature config:
const scheduler = new Scheduler({
features : {
dependencies : {
allowDropOnEventBar : false
}
}
});
Scheduler Pro v4.3.0
Buttons with menus shows a caret down arrow icon
Button has a new config menuIcon that specifies an icon to show when the button has a menu. It defaults to show a caret down arrow icon. If you are using buttons with menus and want to get rid of this icon (for example if you are already displaying a hamburger icon), set menuIcon : null on the button.
Old code:
const button = new Button({
icon : 'fa fa-bars',
menu : [
{ text : 'First item'},
{ text : 'Second item'}
]
})
New code:
const button = new Button({
icon : 'fa fa-bars',
menuIcon : null,
menu : [
{ text : 'First item'},
{ text : 'Second item'}
]
})
Buttons menuIconCls deprecated
Buttons menuIconCls was deprecated in favor of the menuIcon config mentioned above. It will be removed in 5.0. Please replace any usages:
Old code:
const button = new Button({
menuIconCls : 'fa fa-bars',
menu : [
{ text : 'First item'},
{ text : 'Second item'}
]
})
New code:
const button = new Button({
menuIcon : 'fa fa-bars',
menu : [
{ text : 'First item'},
{ text : 'Second item'}
]
})
Scheduler Pro v4.3.7
PdfExport feature
beforeExport SchedulerPro event has been renamed to beforePdfExport and export event has been renamed to pdfExport respectively. Please modify your code to match the new names.
Old code:
scheduler.on({
beforeExport({ config }) { /*...*/ },
export({ config }) { /*...*/ }
})
New code:
scheduler.on({
beforePdfExport({ config }) {
const { orientation } = config;
/*...*/
},
pdfExport({ config }) {
const { orientation } = config;
/*...*/
}
});
Also the events signature had deprecated properties copied from config section which have been removed in this release.