Features
This tutorial shows how to create a web application with scheduler UI using Angular CLI. It uses a backend implemented in Java using Spring Boot framework.
Frontend (angular-scheduler-spring-frontend directory):
Angular 11
Scheduler UI built using DayPilot Angular Scheduler component
Resources (rows) and events are loaded from the backend using REST HTTP call
Supports event creating using drag and drop
Event moving using drag and drop
Includes a trial version of DayPilot Pro for JavaScript (see License below)
Backend (angular-scheduler-spring-backend directory):
Implemented in Java
Uses Spring Boot framework
Set of simple REST/JSON endpoints
In-memory H2 database that is initialized (schema) on startup automatically
Hibernate/JPA is used for ORM
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.
Angular Frontend Project (TypeScript)
1. Create a New Angular CLI Project
Create a project using Angular CLI:
ng new angular-scheduler-spring-frontend
2. Install DayPilot Pro Angular Package
Install DayPilot Pro package from npm.daypilot.org:
npm install https://npm.daypilot.org/daypilot-pro-angular/trial/2020.4.4807.tar.gz --save
3. Create a New Scheduler Module
Create a new module in src/app/scheduler/scheduler.module.ts:
import {DataService} from "./data.service";
import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from "@angular/core";
import {SchedulerComponent} from "./scheduler.component";
import {DayPilotModule} from "daypilot-pro-angular";
import {HttpClientModule} from "@angular/common/http";
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
DayPilotModule
],
declarations: [
SchedulerComponent
],
exports: [SchedulerComponent],
providers: [DataService]
})
export class SchedulerModule {
}
All Scheduler-related code will be located in this module. We will minimize changes to the files generated by Angular CLI (such as app.module.ts
, app.component.ts
) in order to make Angular CLI version upgrade easier (new Angular CLI versions are released often and upgrade requires updating all generated code).
Note that it is necessary to add DayPilotModule
from daypilot-pro-angular
package to the imports. We also declare SchedulerComponent
and DataServices
- two classes that we are going to create in the following steps.
The generated files require the following two modifications:
1. Change src/app/app.component.html
as follows:
<scheduler-component></scheduler-component>
2. Import SchedulerModule
in src/app/app.module.ts
:
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {AppComponent} from './app.component';
import {SchedulerModule} from "./scheduler/scheduler.module";
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
SchedulerModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
4. Create Angular Scheduler Component
Create a new SchedulerComponent
class in src/app/scheduler/scheduler.component.ts
:
import {Component} from '@angular/core';
@Component({
selector: 'scheduler-component',
template: `
<daypilot-scheduler></daypilot-scheduler>
`,
styles: [``]
})
export class SchedulerComponent {
}
5. Scheduler Configuration
Add "scheduler", "events" and "config" properties to SchedulerComponent class in src/app/scheduler/scheduler.component.ts:
import {Component, ViewChild} from '@angular/core';
import {DayPilotSchedulerComponent} from "daypilot-pro-angular";
@Component({
selector: 'scheduler-component',
template: `
<div class="body">
<h1>Scheduler</h1>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
</div>
`,
styles: [`
.body {
padding: 10px;
}
`]
})
export class SchedulerComponent {
@ViewChild("scheduler")
scheduler: DayPilotSchedulerComponent;
events: DayPilot.EventData[];
config: DayPilot.SchedulerConfig = {
timeHeaders : [
{groupBy: "Month", format: "MMMM yyyy"},
{groupBy: "Day", format: "d"}
],
days: 31,
startDate: "2021-10-01",
scale: "Day"
};
}
If we run the Angular application now using ng serve
we will see a page with empty Scheduler control at http://localhost:4200/
:
Because the backend project will run on a different port (8081) we'll add a proxy configuration that will forward local /api
requests to the backend server (http://localhost:8081/api
):
proxy.conf.json:
{
"/api": {
"target": "http://localhost:8081",
"secure": false
}
}
We need to specify the proxy configuration when running the Angular CLI serve
command:
ng serve --proxy-config proxy.conf.json
For your convenience, it's also added to the "start"
script in package.json
so you can run the development server simply by calling:
npm run start
Spring Boot Backend Project (Java)
1. Create a New Spring Boot Project
Create a new Maven project that will use org.springframework.boot:spring-boot-starter-parent
project as a parent.
Add the following dependencies:
org.springframework.boot:spring-boot-starter-web
org.springframework.boot:spring-boot-starter-data-jpa
com.fasterxml.jackson.datatype:jackson-datatype-jsr310
com.h2database:h2
Our Scheduler backend project will use Hibernate and H2 database for DB persistence:
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.1</version>
<relativePath/>
</parent>
<groupId>org.daypilot.demo</groupId>
<artifactId>angular-scheduler-spring-backend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!-- add: -->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
2. Create Spring Boot Application Class
Create org.daypilot.demo.angularscheduler.Application
class:
package org.daypilot.demo.angularscheduler;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
@EntityScan(
basePackageClasses = { Application.class, Jsr310JpaConverters.class }
)
@SpringBootApplication
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
3. Create Domain Classes (JPA/Hibernate)
Create JPA domain classes (Event
and Resource
classes in org.daypilot.demo.angularscheduler.domain
package):
Event.java
package org.daypilot.demo.angularscheduler.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.IDENTITY)
Long id;
String text;
LocalDateTime start;
LocalDateTime end;
@ManyToOne
@JsonIgnore
Resource resource;
@JsonProperty("resource")
public Long getResourceId() {
return resource.getId();
}
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 Resource getResource() {
return resource;
}
public void setResource(Resource resource) {
this.resource = resource;
}
}
Resource.java
package org.daypilot.demo.angularscheduler.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Resource {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
Long Id;
String name;
public Long getId() {
return Id;
}
public void setId(Long id) {
this.Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4. Configure H2 Database (In-Memory)
Create application.properties
file in src/main/resource
directory and add the following properties:
spring.datasource.url=jdbc:h2:mem:mydb
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create
spring.jackson.serialization.write_dates_as_timestamps=false
server.port=${port:8081}
This configuration will create an in-memory H2 database (called mydb
) on application startup and automatically create the database schema from the domain classes (spring.jpa.hibernate.ddl-auto
property).
The spring.h2.console.enabled
property enables the built-in H2 database console which you can use to manage the database (http://localhost:8081/h2console
).
We have also added spring.jackson.serialization.write_dates_as_timestamps
property which will fix date object JSON serialization (see below).
The server.port
propety changes the default 8080 port to 8081 to avoid conflicts with a local Tomcat server installation.
5. Initialize the Database with Sample Resource Data
We will initialize the database with some data using data.sql
file (src/main/resources directory):
insert into resource (name) values ('Resource 1');
insert into resource (name) values ('Resource 2');
insert into resource (name) values ('Resource 3');
6. Create the DAO Classes
Create the repository (data access) classes in org.daypilot.demo.angularscheduler.repository
package:
ResourceRepository.java
package org.daypilot.demo.angularscheduler.repository;
import org.daypilot.demo.angularscheduler.domain.Resource;
import org.springframework.data.repository.CrudRepository;
public interface ResourceRepository extends CrudRepository<Resource, Long> {
}
EventRepository.java
package org.daypilot.demo.angularscheduler.repository;
import org.daypilot.demo.angularscheduler.domain.Event;
import org.springframework.data.repository.CrudRepository;
public interface EventRepository extends CrudRepository<Event, Long> {
}
7. Create the Controller with REST/JSON Endpoints
Create a new MainController
class in org.daypilot.demo.angularscheduler.controller
package:
package org.daypilot.demo.angularscheduler.controller;
import org.daypilot.demo.angularscheduler.domain.Event;
import org.daypilot.demo.angularscheduler.domain.Resource;
import org.daypilot.demo.angularscheduler.repository.EventRepository;
import org.daypilot.demo.angularscheduler.repository.ResourceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
@RestController
public class MainController {
@Autowired
EventRepository er;
@Autowired
ResourceRepository rr;
@RequestMapping("/api")
@ResponseBody
String home() {
return "Welcome!";
}
}
8. Test
Now you can run the application and test the REST API using http://localhost:8081/api
. It returns the welcome string:
Welcome!
Integrating Angular Scheduler Application with Spring Boot Backend
1. DataService Class for Communication with the Backend
First we will create a helper DataService
that will make calls to the backend JSON API and return the results using an Observable.
The empty DataService
will look like this:
import {HttpClient} from "@angular/common/http";
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {DayPilot} from 'daypilot-pro-angular';
@Injectable()
export class DataService {
constructor(private http : HttpClient){
}
}
We need to register the DataService
class as a provider in scheduler.module.ts:
// ...
@NgModule({
// ...
providers: [
DataService
],
// ...
})
// ...
We will also ask for an instance of DataService
to be injected into SchedulerComponent
class (scheduler.component.ts
) so we can use it:
// ...
export class SchedulerComponent {
// ...
constructor(private ds: DataService) {}
// ...
}
2. Loading Scheduler Resources in Angular and Spring
We want to load the Scheduler rows (resources) as soon as the SchedulerComponent
is displayed.
package org.daypilot.demo.angularscheduler.controller;
import org.daypilot.demo.angularscheduler.domain.Event;
import org.daypilot.demo.angularscheduler.domain.Resource;
import org.daypilot.demo.angularscheduler.repository.EventRepository;
import org.daypilot.demo.angularscheduler.repository.ResourceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
@RestController
public class MainController {
@Autowired
EventRepository er;
@Autowired
ResourceRepository rr;
@RequestMapping("/")
@ResponseBody
String home() {
return "Welcome!";
}
@RequestMapping("/api/resources")
Iterable<Resource> resources() {
return rr.findAll();
}
}
The new endpoint (/api/resources
) returns an array of resources in JSON format:
[{"name":"Resource 1","id":1},{"name":"Resource 2","id":2},{"name":"Resource 3","id":3}]
Now we want to request the resource data using the Angular frontend and pass it to the Scheduler:
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="body">
<h1>Scheduler</h1>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
</div>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
// ...
constructor(private ds: DataService) {}
ngAfterViewInit(): void {
this.ds.getResources().subscribe(result => this.config.resources = result);
}
}
3. Loading Scheduler Events in Angular and Spring
In order to load the event data from the server we will add events()
method to MainController
class.
This method will be mapped to /api/events
endpoint. It requires the data range to be specified using from
and to
query string parameters (/api/events?from=2021-10-01T00:00:00&to=2021-11-01T00:00:00
).
package org.daypilot.demo.angularscheduler.controller;
import java.time.LocalDateTime;
import javax.transaction.Transactional;
import org.daypilot.demo.angularscheduler.domain.Event;
import org.daypilot.demo.angularscheduler.domain.Resource;
import org.daypilot.demo.angularscheduler.repository.EventRepository;
import org.daypilot.demo.angularscheduler.repository.ResourceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
@RestController
public class MainController {
@Autowired
EventRepository er;
@Autowired
ResourceRepository rr;
@RequestMapping("/api")
@ResponseBody
String home() {
return "Welcome!";
}
@RequestMapping("/api/resources")
Iterable<Resource> resources() {
return rr.findAll();
}
@GetMapping("/api/events")
@JsonSerialize(using = LocalDateTimeSerializer.class)
Iterable<Event> events(@RequestParam("from") @DateTimeFormat(iso=ISO.DATE_TIME) LocalDateTime from, @RequestParam("to") @DateTimeFormat(iso=ISO.DATE_TIME) LocalDateTime to) {
return er.findBetween(from, to);
}
}
Angular:
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="body">
<h1>Scheduler</h1>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
</div>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler")
scheduler: DayPilotSchedulerComponent;
// ...
constructor(private ds: DataService) {}
ngAfterViewInit(): void {
this.ds.getResources().subscribe(result => this.config.resources = result);
var from = this.scheduler.control.visibleStart();
var to = this.scheduler.control.visibleEnd();
this.ds.getEvents(from, to).subscribe(result => this.events = result);
}
}
4. Creating Events using Drag and Drop in Angular and Spring
We will handle the onTimeRangeSelected event of the Scheduler to create a new event. But first, we need to create the JSON endpoint in the backend.
The event handler is specified using onTimeRangeSelected
property of the config object.
It displays a simple prompt dialog to get the new event name.
It calls
/api/events/create
endpoint to store the new event. The endpoint returns event data object.We wait until the new event data object is returned and we add it to the
events
array.The Scheduler displays it as soon as the change of
events
is detected.
Angular Frontend: SchedulerComponent (scheduler.component.ts)
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService, CreateEventParams} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="body">
<h1>Scheduler</h1>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
</div>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
// ...
@ViewChild("scheduler")
scheduler: DayPilotSchedulerComponent;
config: DayPilot.SchedulerConfig = {
timeHeaders : [
{groupBy: "Month", format: "MMMM yyyy"},
{groupBy: "Day", format: "d"}
],
days: 31,
startDate: "2021-10-01",
scale: "Day",
onTimeRangeSelected: args => {
DayPilot.Modal.prompt("New event name:", "Event").then(modal => {
this.scheduler.control.clearSelection();
if (!modal.result) {
return;
}
let params: EventCreateParams = {
start: args.start.toString(),
end: args.end.toString(),
text: modal.result,
resource: args.resource
};
this.ds.createEvent(params).subscribe(result => {
this.events.push(result);
this.scheduler.control.message("Event created");
} );
});
},
};
// ...
}
Angular Frontend: DataService class (data.service.ts)
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {DayPilot} from 'daypilot-pro-angular';
import {HttpClient} from "@angular/common/http";
@Injectable()
export class DataService {
constructor(private http : HttpClient){
}
// ...
createEvent(data: EventCreateParams): Observable<EventData> {
return this.http.post("/api/events/create", data) as Observable<any>;
}
}
export interface EventCreateParams {
start: string;
end: string;
text: string;
resource: string | number;
}
export interface EventData {
id: string | number;
start: string;
end: string;
text: string;
resource: string | number;
}
Spring Boot Backend: MainController.java
package org.daypilot.demo.angularscheduler.controller;
// ...
@RestController
public class MainController {
@Autowired
EventRepository er;
@Autowired
ResourceRepository rr;
// ...
@PostMapping("/api/events/create")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@Transactional
Event createEvent(@RequestBody EventCreateParams params) {
Resource r = rr.findOne(params.resource);
Event e = new Event();
e.setStart(params.start);
e.setEnd(params.end);
e.setText(params.text);
e.setResource(r);
er.save(e);
return e;
}
public static class EventCreateParams {
public LocalDateTime start;
public LocalDateTime end;
public String text;
public Long resource;
}
}
5. Drag and Drop Event Moving in Angular and Spring Boot
Event moving is enabled by default in the Scheduler.
We need to handle onEventMove event and notify the server about the new location.
This time we don't update the event data in
events
array. It will be updated automatically (the default eventMoveHandling action is set to"Update"
).
Angular Frontend: SchedulerComponent
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService, CreateEventParams, MoveEventParams} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="body">
<h1>Scheduler</h1>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
</div>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler")
scheduler: DayPilotSchedulerComponent;
// ..
config: DayPilot.SchedulerConfig = {
// ...
onEventMove: args => {
let params: MoveEventParams = {
id: args.e.id(),
start: args.newStart.toString(),
end: args.newEnd.toString(),
resource: args.newResource
};
this.ds.moveEvent(params).subscribe(result => {
this.scheduler.control.message("Event moved");
});
}
};
constructor(private ds: DataService) {}
// ...
}
Angular Frontend: DataService
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs';
import {DayPilot} from 'daypilot-pro-angular';
import {HttpClient} from "@angular/common/http";
@Injectable()
export class DataService {
constructor(private http : HttpClient){
}
// ...
moveEvent(data: EventMoveParams): Observable<EventData> {
return this.http.post("/api/events/move", data) as Observable<any>;
}
}
export interface EventMoveParams {
id: string | number;
start: string;
end: string;
resource: string | number;
}
export interface EventData {
id: string | number;
start: string;
end: string;
text: string;
resource: string | number;
}
Spring Boot Backend: MainController.java
package org.daypilot.demo.angularscheduler.controller;
// ...
@RestController
public class MainController {
@Autowired
EventRepository er;
@Autowired
ResourceRepository rr;
// ...
@PostMapping("/api/events/move")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@Transactional
Event moveEvent(@RequestBody EventMoveParams params) {
Event e = er.findOne(params.id);
Resource r = rr.findOne(params.resource);
e.setStart(params.start);
e.setEnd(params.end);
e.setResource(r);
er.save(e);
return e;
}
public static class EventMoveParams {
public Long id;
public LocalDateTime start;
public LocalDateTime end;
public Long resource;
}
}
6. Deleting Events in Angular and Spring
The Angular Scheduler component includes built-in support for event deleting. It is disabled by default but we can enable it easily using eventDeleteHandling property:
config: DayPilot.SchedulerConfig = {
eventDeleteHandling: "Update",
// ...
}
When the deleting is enabled, the Scheduler will display a delete icon in the upper-right corner of the Scheduler events on hover.
If you click the delete icon the Scheduler fires onEventDelete event handler. We will use it to notify the Spring Boot backend and delete the event record from the database. The Scheduler UI will be updated automatically (this is ensured by setting eventDeleteHandling
to "Update"
).
config: DayPilot.SchedulerConfig = {
eventDeleteHandling: "Update",
onEventDelete: args => {
let params: EventDeleteParams = {
id: args.e.id(),
};
this.ds.deleteEvent(params).subscribe(result => {
this.scheduler.control.message("Event deleted");
});
},
//...
}
The server-side Spring Boot endpoint looks like this:
package org.daypilot.demo.angularscheduler.controller;
// ...
@RestController
public class MainController {
@Autowired
EventRepository er;
@PostMapping("/api/events/delete")
@Transactional
void deleteEvent(@RequestBody EventDeleteParams params) {
er.deleteById(params.id);
}
public static class EventDeleteParams {
public Long id;
}
// ...
}
Spring Boot Gotchas
Enable java.time.* classes in Hibernate
In order to handle the Java 8 DateTime objects properly in the domain classes it's necessary to add Jsr310JpaConverters.class
to @EntityScan
annotation of the Application
class:
@EntityScan(
basePackageClasses = { Application.class, Jsr310JpaConverters.class }
)
Without this setting, the LocalDateTime
fields of domain classes won't be created as TIMESTAMP in the database.
Serialize the resource reference as plain id in JSON
We are using the original domain classes for JSON serialization so we need to flatten the structure - replace the Resource reference with a resource id.
Original (Resource.java):
@ManyToOne
Resource resource;
Updated (Resource.java):
@ManyToOne
@JsonIgnore
Resource resource;
@JsonProperty("resource")
public Long getResourceId() {
return resource.getId();
}
Serialize the dates in ISO format in JSON
In order to serialize DateTime
objects to JSON properly (as a ISO 8601 string) we need to add com.fasterxml.jackson.datatype:jackson-datatype-jsr310 package as a dependency and add the following property to application.properties
:
spring.jackson.serialization.write_dates_as_timestamps=false
History
December 16, 2020: Spring Boot upgraded to 2.4.1. DayPilot Pro upgraded to 2020.4.4807. Angular 11.
September 25, 2019: Spring Boot upgraded to 2.1.8. Running on JDK 11+. DayPilot Pro upgraded to 2019.3.4012. Angular 8. Event deleting added.
June 11, 2018: DayPilot Pro upgraded to version 2018.2.3297. Using Angular CLI 6.0 and Angular 6.
April 6, 2017: DayPilot Pro upgraded to version 8.3.2805. Using Angular CLI 1.0 and Angular 4.
February 22, 2017: DayPilot Pro upgraded to version 8.3.2721. All Scheduler-related code moved to SchedulerModule to allow easy Angular CLI upgrade.
November 21, 2016: Initial release, Angular 2