Blog post Technical, Kentico, Custom Development

Kentico MVC FullCalendar widget

With the latest Kentico 12 Service Pack 1, Kentico not only introduced a bunch of new features for Kentico EMS, but they put focus a lot on the global Kentico developer community. Developers are encouraged to build their own extensions to Widgets, Sections and Page Templates, and maintain them as open-source projects, published on the Kentico DevNet Marketplace.

EXLRT has published a few contributions to the marketplace already, and now we want to offer a custom calendar widget to the community, supporting reusability across projects with only minor design and configuration tweaks. This widget follows typical Kentico design principles by using Page types, Custom tables and Module classes to model content elements that, in this case, represent calendar events.

For the widget UI, we chose FullCalendar, a free, open-source jQuery plug-in that's modular and, support customizations. We picked a few configurations that we considered to be good to start with, but it’s possible to customize things easily.

The widget uses two other front-end technologies worth mentioning: Popper and Tooltip. With Tooltip, we can display additional content for a particular event very elegantly.

Calendar view with a popup for multiple events on same day
Calendar view with a popup for multiple events on same day

The basic idea of this widget is to allow content editors to put it anywhere on the website and to select which data will be displayed. We thought it could be a potential risk to give full configuration control to editors. It's because they would have to be familiar with a lot of different content structures they usually don’t use; column names of specific page type fields, class names, object names, etc.

In our experience, giving editors so many options doesn’t work as expected, because, in the end, developers are the ones who will need to make final configurations each time. All this pushed us to simplify as much as possible for content editors and allow them only to work with a predefined set of calendar configurations that are made by developers.

To summarize everything one more time. If you want to use this widget in your project, you need to:

  1. Setup Full calendar Kentico MVC widget
  2. Configure a predefined set of calendar configurations
  3. Modify CSS / JS files to match design requirements
  4. Add a widget in any defined widget section and select a calendar configuration that you want to utilize

The calendar widget can be installed in two ways, either through a NuGet package or by downloading a copy of the source code from our GitHub repository.

While installation through NuGet is more straightforward, you get more flexibility and options to customize by using the source code, e.g., adding support for additional event properties or other metadata. In this blog, we'll cover only the installation through the NuGet package. But you can find more details about using the full source code and necessary configuration on this here.

To install the calendar widget through NuGet you need to:

  1. Download NuGet package from this link
  2. Setup a local NuGet feed and copy the NuGet package file EXLRT.Kentico.Mvc.Widgets.FullCalendar.1.0.0.nupkg to the newly created feed location.
  3. Install the package in your MVC project through NuGet package manager

After completing those steps, you will have all of the necessary files for your solution.

Next, we can start with the configuration. We need to:

  1. Register routes for the new API
  2. Setup Dependency Injection
  3. Include style and script rendering in the Layout view
  4. Create a set of calendar types that will be available for the widget

Calendar types can be specific per site, but they need to have unique widget types known globally. All this can be done with a few lines of code.

To register the API route, you need to call the MapFullCalendarRoutes method (see code snippet below), which represents an extension method to RouteCollection and it resides within the EXLRT.Kentico.Mvc.Widgets.FullCalendar namespace.

This API is an MVC controller, responsible for retrieving events data from Kentico. Based on the calendar code name (widget type), the right configuration is loaded to initialize the widget, and it will let Kentico get the data and render it through the calendar widgets view. This controller can be extended to support any external data. The only requirement is that all output should be mappable to the type FullCalendarEvent.

void MapFullCalendarRoutes(this RouteCollection routes, MvcRouteHandler routeHandler = null, object constraint = null, CultureInfo defaultCulture = null);

Guidelines on how to set up Dependency Injection can be taken from the DancingGoat demo website. To register DI properly, you need to call extend method (see code snippet below) called RegisterFullCalendarDependencies on the ContainerBuilder. That’s why we need a dependency on Autofac 3.5.2.

void RegisterFullCalendarDependencies(this ContainerBuilder builder);

To allow FullCalendar to be initialized and styled correctly, you would need to include styles RenderFullCalendarStyles and scripts RenderFullCalendarScripts on the master layout (see code snippet below). It’s important to note that RenderFullCalendarScripts is registered after the jQuery bundle because jQuery is needed to initialize the calendar widget properly.

The extension mentioned above methods can be found within the Kentico.Mvc.Widgets.FullCalendar.Extensions namespace.

@using EXLRT.Kentico.Mvc.Widgets.FullCalendar.Extensions;
...
<head>
	...
	 @Html.RenderFullCalendarStyles()
</head>
<body>
	...
	@Html.RenderFullCalendarScripts();
</body>

We configure predefined widget types (see code snippet below) at the Application initialization stage; at the beginning of the application lifecycle. We have to define the data structure that will be used to store and retrieve data, and we do this through the FullCalendarConfigurationType enumeration.

While you're free to choose any data structure, there are a few mandatory columns like Title, StartDate, EndDate. Some optional columns would be Description (shown in a tooltip), AllDay, and Url. The Url implementation differs a bit from other columns because it needs additional data to generate the URL corectly.

For multi-cultural sites use the InitializeFullCalendarForMultiCultureSites method, otherwise you can stick to InitializeFullCalendarForSingleCultureSites. This will affect routing and generating the necessary scripts for the Full calendar widget, such as localization.

using EXLRT.Kentico.Mvc.Widgets.FullCalendar;
...
FullCalendarConfiguration.InitializeFullCalendarForMultiCultureSites()
                    .AddConfiguration("articles", FullCalendarConfigurationType.Pages, "DancingGoatMvc.Article",
                                      "Articles (Pages)", "DocumentName", "DocumentPublishFrom", "DocumentPublishTo", new UrlConfiguration()
                                      {
                                          Pattern = "/#DocumentCulture#/Articles/#NodeGUID#/#NodeAlias#",
                                          Columns = new string[] { "DocumentCulture", "NodeAlias", "NodeGUID" }
                                      });

All default HTML markup for the widget is in the partial view _FullCalendarWidget.cshtml. We'd encourage you to review this file first and make sure it matches the look and feel of your site. Just don’t remove the @Html.IntializeCalendar() snippet!

The file path for the CSS is /Content/Widgets/FullCalendar/css/fullCalendar.css, and JavaScript's is /Content/Widgets/FullCalendar/js/fullCalendar.js.

It’s up to you whether you want to modify CSS directly or create your own file to override style definitions. You could also add support for additional properties and handle them in the fullCalendar.js file (check the official documentation here). You would typically modify the customizeCalendarEvent method for that (see code snippet below).

function customizeCalendarEvent(config, info) {
    if (info.event.extendedProps.description) {
        …

        if (config.useTooltip === 'True') {
            …
        }
        …
    }
    …
}

Once a widget is initially added to the page, a message ‘Full calendar widget does not have proper configuration!’ is displayed. That’s fine! It's just a friendly reminder for content editors that they should select a calendar configuration from the predefined set. They can do this from widget properties dialog (see image 2 below). The other properties are just a few that we decided to go with, but this can be extended to almost every property that the full calendar supports.

After selecting a calendar from the list, data will be instantly loaded on the page and you'll be able to see all events of a specific calendar type.

Full calendar properties model dialog
Full calendar properties model dialog

One potential improvement could be moving all configuration directly to Kentico as a custom module or to custom tables and then handling everything directly from the Kentico UI. This would mean you'd not need to redeploy the widget after the configuration has changed. It would also result in a much larger installation package and create dependencies with Kentico versioning. This isn’t a usual requirement, but we could add it in future versions. Or you could do it yourself, of course.

More examples of configuring this widget for the DancingGoat demo website are at this link.

Contact us to discuss your project.
We're ready to work with you.
Let's talk