v7.3.0

Upgrade guides for Calendar v4.0.0+

Calendar 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 Calendar was bumped from 1.0 -> 4.0 to bring it in line with Grid, Scheduler, Scheduler Pro and Gantt. 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.

New calendar.lite.umd.js version to use with Angular

Bryntum Calendar is delivered with a new UMD package without polyfills. This was done to avoid conflicts with any external Promise polyfills, such as ZoneAwarePromise from zone.js for Angular applications. It fixes this runtime error:

Zone.js has detected that ZoneAwarePromise (window|global).Promise has been overwritten.
Most likely cause is that a Promise polyfill has been loaded after Zone.js 
(Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)

We recommend that all your Angular applications should be upgraded to use the new calendar.lite.umd.js bundle. Also, there should be no polyfills imported in app/src/polyfills.ts after import 'zone.js/dist/zone';. We have updated all our Angular examples to use this new bundle. Make sure to update all usages of calendar.umd.js to calendar.lite.umd.js within your application to avoid Bundle included twice runtime error.

Old code:

import { Calendar, EventModel, EventStore } from 'bryntum-calendar/calendar.umd.js';

New code:

import { Calendar, EventModel, EventStore } from 'bryntum-calendar/calendar.lite.umd.js';

Event selection and keyboard navigation

Basic support for selecting events using the mouse and keyboard navigation by tabbing between events was added. When navigating using the keyboard, the active event is clearly outlined.

Exporting events to iCal

Calendar can now export individual events in .ics format. The downloaded file can be imported into any calendar software supporting the standard, such as Google Calendar, Outlook, Apple Calendar and many more. For more information please see TimeSpan#exportToICS() in the API docs.

Load on demand

Calendar now triggers a dateRangeChange event before a view displays events for a new range of dates. By listening to that event you can for example load events on demand or update some other linked part of the UI you might have implemented.

For the load on demand scenario, there is a new feature called LoadOnDemand that assists with this if you are using CrudManger to load your data. It will append start and end dates of the date range to the server requests made, allowing you to easily return events inside the currently viewed range.

Changed event triggering timing

The stores that are part of the project (EventStore, ResourceStore) 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:

  • add
  • remove
  • removeAll
  • change
  • refresh

Consider the following scenario:

const calendar = new Calendar({
    events : [/*...*/],

    listeners : {
        add({ records }) {
            console.assert(records[0].endDate)
        }
    }
});

calendar.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'
    }
], /*...*/);

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 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 {
/*...*/
}

Calendar v4.0.4

The following properties were made private in DayCellRenderer#dayCellRenderer and AgendaView#dayCellRenderer, relying on their existence not recommended:

  • key
  • data
  • visibleColumnIndex
  • isOtherMonth
  • visible
  • tomorrow
  • isRowStart
  • isRowEnd
  • renderedEvents

Calendar v4.1.0

Be sure to also check out the news in Grid and Scheduler.

AgendaView has configurable time range

Prior to version 4.1.0, the Agenda View simply iterated existing events in the store, and created a row for each date that had events intersecting it.

This meant that recurring events were not projected into the future in AgendaView.

From 4.1.0, Agenda View has a range config which may take the following values:

  • day
  • week
  • month
  • year
  • decade

A magnitude part may also be included, eg:

modes : {
    agenda : {
        range : '3 months'
    }
}

A floating button in the Agenda View allows the user to choose the range they wish to see.

New view type list

A list view is a grid-based view of the events in the store showing the event fields in columns.

This view has a range in the same way as the Agenda View. The menu to choose the range to display is part of the header context menu.

This view is not shown by default, but will need to be configured in if required:

    modes : {
        list : true
    }

Dropped support for RequireJS

In version 4.1.0 we have removed the RequireJS demo from the project, since it is an outdated technology. We instead recommend using modern ES6 module imports which is supported in all modern browsers (Chrome, FireFox, Safari, Edge (chromium)).

You could easily upgrade old application code to use new technology.

Old code:

index.html

<script data-main="scripts/app" src="scripts/require.js"></script>

scripts/app.js

requirejs.config({
    paths : {
        calendar : '../../../build/calendar.umd'
    }
});

requirejs(['calendar'], function(bryntum) {
    new bryntum.Calendar({
        // config here
    });
});

New code:

index.html

<script type="module" src="scripts/app.js"></script>

scripts/app.js

import { Calendar } from '../../../build/calendar.module.js';

new Calendar({
    // config here
});

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.

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

Calendar v4.1.1

Wrapper dependencies

In order to support installing trial package alias for wrappers they now require adding @bryntum/calendar dependency to application's package.json file.

Example for licensed version for Angular framework:

{
  "dependencies": {
    "@bryntum/calendar": "4.1.1",
    "@bryntum/calendar-angular": "4.1.1"
  }
}

Example for trial version for Angular framework:

{
  "dependencies": {
    "@bryntum/calendar": "npm:@bryntum/calendar-trial@4.1.1",
    "@bryntum/calendar-angular": "4.1.1"
  }
}

Calendar v4.2.4

Gap between events

DayView has a new config named eventSpacing which is used to reduce the height of all events in day and week views to leave a small gap between them. This new appearance is used by default (eventSpacing defaults to 1).

In previous versions this gap was faked using a gray bottom border on the events. If you prefer the old appearance, you can configure eventSpacing: 0 and apply a bottom border using CSS:

const calendar = new Calendar({
    modes : {
        day : {
            // Remove the gap between events
            eventSpacing : 0
        }
    }
});
/* Add bottom border to events in day & week views */
.b-dayview-day-container .b-cal-event {
    border-bottom    : 1px solid #ddd;
}

Calendar 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'}
    ]
})

Contents