Features

  • Java 8
  • Spring Boot 1.5
  • Maven project configuration
  • Data persistence using Spring Data/JPA
  • Separate frontend (HTML5/JavaScript) and backend (Spring web service)
  • Includes a trial version of DayPilot Pro for JavaScript (see License below)

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

Monthly Calendar Control Initialization

html5-javascript-monthly-event-calendar-spring-boot-java-initialization.png

The minimum code required to use a JavaScript monthly event calendar in an HTML5 page:

<!-- monthly calendar control placeholder -->
<div id="dp"></div>

<!-- DayPilot library -->
<script src="js/daypilot/daypilot-all.min.js"></script>

<!-- calendar initialization and config -->
<script>

    var dp = new DayPilot.Month("dp");
    dp.init();
    
</script>

Hiding Weekends

html5-javascript-monthly-event-calendar-spring-boot-java-hiding-weekend.png

In the default configuration, the monthly calendar displays full week including weekends (Saturday and Sunday).

We will add a simple checkbox that will allow users to select a view with or without weekends. 

HTML5

<label><input type="checkbox" id="weekends" checked="checked"> Show weekend</label>

JavaScript

$("#weekends").click(function() {
  dp.showWeekend = $("#weekends").is(":checked");
  dp.update();
});

When the checkbox value changes, we set the showWeekend property according to the selection and redraw the monthly calendar using update() method.

Loading and Displaying Events in the Monthly Calendar

html5-javascript-monthly-event-calendar-spring-boot-java-loading-events.png

We will load the event data using an AJAX call from a REST/JSON endpoint. The monthly calendar control supports a convenience method for loading event data from a specified URL:

dp.events.load("/api/events");

The URL will be automatically extended with the start and end date of the current month view. The start and end dates will be added as query string parameters:

http://localhost:8081/api/events?start=2017-10-01T00:00:00&end=2017-11-05T00:00:00

The /api/events URL is handled by a Spring controller on the server side (CalendarController.java). It returns event data for the specified date range:

package org.daypilot.demo.html5eventcalendarspring.controller;

// ...

@RestController
public class CalendarController {

    @Autowired
    EventRepository er;


    @GetMapping("/api/events")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    Iterable<Event> events(@RequestParam("start") @DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime start, @RequestParam("end") @DateTimeFormat(iso = ISO.DATE_TIME) LocalDateTime end) {
        return er.findBetween(start, end);
    }

    // ...

}

Event Deleting using a Context Menu

html5-javascript-monthly-event-calendar-spring-boot-java-delete-context-menu.png

We will add a context menu to events. It will let users delete the event.

The context menu can be created using contextMenu property of the DayPilot.Month object. It's a DayPilot.Menu object that specifies menu items (including text and click event handler).

HTML5 view

dp.contextMenu = new DayPilot.Menu({
    items: [
        {
            text: "Delete",
            onClick: function(args) {
                var e = args.source;
                var params = {
                    id: e.id()
                };
                $.ajax({
                    type: 'POST',
                    url: '/api/events/delete',
                    data: JSON.stringify(params),
                    success: function (data) {
                        dp.events.remove(e);
                        dp.message("Deleted");
                    },
                    contentType: "application/json",
                    dataType: 'json'
                });
            }
        }

    ]
});

By default, the context menu will be opened on right click. Since it's not obvious that this option is available, we will add a context menu hint to the event box using an event active area. The active area uses "ContextMenu" as its action - this opens the default context menu specified using DayPilot.Month.contextMenu property.

dp.onBeforeEventRender = function(args) {
    args.data.areas = [
        { top: 4, right: 4, icon: "icon-triangle-down", visibility: "Hover", action: "ContextMenu", style: "font-size: 12px; background-color: #fff; border: 1px solid #ccc; padding: 2px 2px 0px 2px; cursor:pointer;"}
    ];
    // ...
};

The "Delete" context menu item uses an AJAX call to delete the item from the monthly calendar. The Spring controller that implements the REST API contains deleteEvent() method that handles calls to "/api/events/delete" URL.

package org.daypilot.demo.html5eventcalendarspring.controller;

// ...

@RestController
public class CalendarController {

    @Autowired
    EventRepository er;


    @PostMapping("/api/events/delete")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @Transactional
    EventDeleteResponse deleteEvent(@RequestBody EventDeleteParams params) {

        er.delete(params.id);

        return new EventDeleteResponse() {{
            message = "Deleted";
        }};
    }

    public static class EventDeleteParams {
        public Long id;
    }

    public static class EventDeleteResponse {
        public String message;
    }

    // ...

}

Custom Event Color

html5-javascript-monthly-event-calendar-spring-boot-java-context-menu.png

Now we will extend our context menu with a list of custom event colors. Selecting the context menu item will update the event color in the database an update it in the monthly calendar in the browser.

dp.contextMenu = new DayPilot.Menu({
    items: [
        {
            text: "Delete",
            onClick: function(args) {
                var e = args.source;
                var params = {
                    id: e.id()
                };
                $.ajax({
                    type: 'POST',
                    url: '/api/events/delete',
                    data: JSON.stringify(params),
                    success: function (data) {
                        dp.events.remove(e);
                        dp.message("Deleted");
                    },
                    contentType: "application/json",
                    dataType: 'json'
                });
            }
        },
        {
            text: "-"
        },
        {
            text: "Blue",
            icon: "icon icon-blue",
            color: "#a2c4c9",
            onClick: function(args) { updateColor(args.source, args.item.color); }
        },
        {
            text: "Green",
            icon: "icon icon-green",
            color: "#b6d7a8",
            onClick: function(args) { updateColor(args.source, args.item.color); }
        },
        {
            text: "Yellow",
            icon: "icon icon-yellow",
            color: "#ffe599",
            onClick: function(args) { updateColor(args.source, args.item.color); }
        },
        {
            text: "Red",
            icon: "icon icon-red",
            color: "#ea9999",
            onClick: function(args) { updateColor(args.source, args.item.color); }
        },            {
            text: "Auto",
            color: "auto",
            onClick: function(args) { updateColor(args.source, args.item.color); }
        },

    ]
});

All color menu items change the color by calling updateColor() JavaScript function:

function updateColor(e, color) {
    var params = {
        id: e.id(),
        color: color
    };
    $.ajax({
        type: 'POST',
        url: '/api/events/setColor',
        data: JSON.stringify(params),
        success: function (data) {
            e.data.color = color;
            dp.events.update(e);
        },
        contentType: "application/json",
        dataType: 'json'
    });
}

The updateColor() function invokes "/api/events/setColor" web service endpoint which is implemented in CalendarController class:

package org.daypilot.demo.html5eventcalendarspring.controller;

// ...

@RestController
public class CalendarController {

    @Autowired
    EventRepository er;

    @PostMapping("/api/events/setColor")
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @Transactional
    Event setColor(@RequestBody SetColorParams params) {

        Event e = er.findOne(params.id);
        e.setColor(params.color);
        er.save(e);

        return e;
    }

    public static class SetColorParams {
        public Long id;
        public String color;
    }

    // ...

}

The "color" property is saved as part of the Event entity class:

package org.daypilot.demo.html5eventcalendarspring.domain;

import java.time.LocalDateTime;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

@Entity
public class Event {
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	Long id;
	
	String text;
	
	LocalDateTime start;
	
	LocalDateTime end;
	
	String color;
	
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public LocalDateTime getStart() {
		return start;
	}

	public void setStart(LocalDateTime start) {
		this.start = start;
	}

	public LocalDateTime getEnd() {
		return end;
	}

	public void setEnd(LocalDateTime end) {
		this.end = end;
	}

	public String getColor() { return color; }

	public void setColor(String color) { this.color = color; }
}

We need to apply the color as the event background color on the client side during rendering. We will use onBeforeEventRender event handler to map the "color" property of the data item to the "backColor" property that specified the background color.

dp.onBeforeEventRender = function(args) {
  args.data.backColor = args.data.color;
  // ...
};

Exporting the Monthly Calendar as Image (SVG, PNG, JPEG)

html5-javascript-monthly-event-calendar-spring-boot-java-export-svg-jpeg-png.png

The monthly calendar control includes built-in support for image export. The exported image is created on the client side from the current view (including the event data).

var output = dp.exportAs("svg");

The export object allows direct download:

dp.exportAs("svg").download("monthly-calendar.svg");

It's also possible to request printing of the exported image directly from the browser:

dp.exportAs("svg").print();