Overview
A quick-start Angular 18 project that includes a pre-configured Scheduler component.
The Angular Scheduler component displays a timeline for multiple resources.
You can use it as a starting point for you own Angular application (project management, reservations, work order scheduling, production planning and other calendar applications).
You can also configure the Angular Scheduler component online using the UI Builder application and generate a new Angular project with your own configuration.
You will learn how to add more Scheduler features to provide richer user interface.
The project 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.
Angular 18 Scheduler Component
Here you can find the minimum configuration required to display the Angular Scheduler component.
Note that the Scheduler component is defined using a <daypilot-scheduler>
tag in the HTML template. The [config]
attribute points to an object with configuration options.
The config
object specifies the Scheduler behavior and appearance. In this minimum configuration, we use startDate
, days
, timeHeaders
and scale
properties to define the timeline.
You can find the component in src/app/scheduler.component.ts
file.
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import {DataService} from './data.service';
@Component({
selector: 'scheduler-component',
standalone: true,
imports: [DayPilotModule],
providers: [DataService],
template: `<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild('scheduler')
scheduler!: DayPilotSchedulerComponent;
events: DayPilot.EventData[] = [];
config: DayPilot.SchedulerConfig = {
timeHeaders: [
{groupBy: "Month"},
{groupBy: "Day", format: "d"}
],
scale: "Day",
days: 31,
startDate: "2024-10-01",
// ...
};
constructor(private ds: DataService) {
}
ngAfterViewInit(): void {
this.ds.getResources().subscribe(result => this.config.resources = result);
}
}
The Angular 18 Scheduler displays custom resources as rows. You can define the rows using the resources
property of the config
object. In this example, we use a special service (DataService
class) to provide the resource data.
In a standard Angular application, you would load the resource data from an HTTP endpoint but we define it statically (for the sake of simplicity).
import {Injectable} from '@angular/core';
import {DayPilot} from 'daypilot-pro-angular';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
@Injectable()
export class DataService {
resources: DayPilot.ResourceData[] = [
{
name: 'Group A', id: 'GA', expanded: true, children: [
{name: 'Resource 1', id: 'R1', capacity: 10},
{name: 'Resource 2', id: 'R2', capacity: 30},
{name: 'Resource 3', id: 'R3', capacity: 20},
{name: 'Resource 4', id: 'R4', capacity: 40}
]
},
{
name: 'Group B', id: 'GB', expanded: true, children: [
{name: 'Resource 5', id: 'R5', capacity: 20},
{name: 'Resource 6', id: 'R6', capacity: 40},
{name: 'Resource 7', id: 'R7', capacity: 20},
{name: 'Resource 8', id: 'R8', capacity: 40}
]
}
];
constructor(private http: HttpClient) {
}
getResources(): Observable<any[]> {
// simulating an HTTP request
return new Observable(observer => {
setTimeout(() => {
observer.next(this.resources);
}, 200);
});
// return this.http.get("/api/resources");
}
}
Row Header Columns with Resource Details
Now we can start adding more properties to the Scheduler config
to enable additional features.
In the first step, we will define row header columns which can display detailed information for resources.
Our example defines two columns:
“Name” - this column displays the default resource name (as defined using
name
property)“Capacity” - this is a custom column that uses data from a
capacity
property
Note that if you add a sort
property the Scheduler component will enable row sorting and users will be able to change the row order using sort icons in the column header. The sort value points to a field of the data source (resource object) that will be used to determine the order. It can be the same value that is displayed in the column (like in this example) or it can be a different field. That is helpful when you display a formatted value (such as a number or currency).
config: DayPilot.SchedulerConfig = {
rowHeaderColumns: [
{text: "Name", display: "name", sort: "name"},
{text: "Capacity", display: "capacity", sort: "capacity"}
],
// ...
};
Context Menu for Scheduler Events
The Scheduler can display a context menu for events where you can define common actions, such as “Edit”, “Delete”, and “Assign”.
We will also add a hover icon as a hint that the context menu is available. Users will be able to open the context menu by right-clicking the event or by clicking the menu icon.
config: DayPilot.SchedulerConfig = {
contextMenu: new DayPilot.Menu({
items: [
{ text: "Edit...",
onClick: async args => {
const e = args.source;
this.editEvent(e);
}
},
{ text: "Delete",
onClick: args => {
const e = args.source;
this.scheduler.control.events.remove(e);
}
}
]
}),
onBeforeEventRender: args => {
args.data.areas = [
{
right: 5,
top: 10,
width: 16,
height: 16,
symbol: "assets/daypilot.svg#minichevron-down-2",
fontColor: "#aaa",
action: "ContextMenu",
style: "border: 1px solid #aaa; border-radius: 50%;",
visibility: "Hover"
}
];
},
// ...
};
Modal Dialog with Scheduler Event Details
To edit the event details, you can use a customizable modal form provided by DayPilot.Modal.form() method. It lets you define custom fields and their mappings to the Angular Scheduler event object.
config: DayPilot.SchedulerConfig = {
onEventClick: args => {
this.editEvent(args.e);
},
};
async editEvent(e: DayPilot.Event): Promise<void> {
const form = [
{ name: "Name", id: "text", type: "text"},
{ name: "Description", id: "description", type: "textarea"}
];
const modal = await DayPilot.Modal.form(form, e.data);
if (modal.canceled) {
return;
}
const updated = modal.result;
this.scheduler.control.events.update(updated);
}
Callout with Event Description
The Angular 18 Scheduler also provides a way to show more event details. The event bubble can display custom HTML on hover.
The easiest way to define the tooltip content is to add a bubbleHtml
property directly to the event data object (you can generate it on the server side or using onBeforeEventRender
event handler):
The callout HTML can also by generated dynamically right before the bubble is displayed using onLoad method.
This example simply displays the value of the description
property but you can use the onLoad
method to load the data from the server using an HTTP call.
config: DayPilot.SchedulerConfig = {
bubble: new DayPilot.Bubble({
onLoad: args => {
args.html = DayPilot.Util.escapeHtml(args.source.data.description || "");
}
}),
// ...
};
Angular Data Service
The DataService
class defines the data access methods:
getEvents()
- returns a Promise that provides an array with Scheduler event datagetResources()
- returns a Promise that provides an array with Scheduler resource data
As we mentioned above, this example defines the data statically. In your Angular application, you will need to update the methods to make an HTTP call to a service that loads the data from a database.
import {Injectable} from '@angular/core';
import {DayPilot} from 'daypilot-pro-angular';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs';
@Injectable()
export class DataService {
resources: DayPilot.ResourceData[] = [
{
name: 'Group A', id: 'GA', expanded: true, children: [
{name: 'Resource 1', id: 'R1', capacity: 10},
{name: 'Resource 2', id: 'R2', capacity: 30},
{name: 'Resource 3', id: 'R3', capacity: 20},
{name: 'Resource 4', id: 'R4', capacity: 40}
]
},
{
name: 'Group B', id: 'GB', expanded: true, children: [
{name: 'Resource 5', id: 'R5', capacity: 20},
{name: 'Resource 6', id: 'R6', capacity: 40},
{name: 'Resource 7', id: 'R7', capacity: 20},
{name: 'Resource 8', id: 'R8', capacity: 40}
]
}
];
events: DayPilot.EventData[] = [
{
id: '1',
resource: 'R1',
start: '2024-10-03',
end: '2024-10-08',
text: 'Scheduler Event 1',
barColor: '#e69138'
},
{
id: '2',
resource: 'R3',
start: '2024-10-02',
end: '2024-10-05',
text: 'Scheduler Event 2',
barColor: '#6aa84f'
},
{
id: '3',
resource: 'R3',
start: '2024-10-06',
end: '2024-10-09',
text: 'Scheduler Event 3',
barColor: '#3c78d8'
}
];
constructor(private http: HttpClient) {
}
getEvents(from: DayPilot.Date, to: DayPilot.Date): Observable<any[]> {
// simulating an HTTP request
return new Observable(observer => {
setTimeout(() => {
observer.next(this.events);
}, 200);
});
// return this.http.get("/api/events?from=" + from.toString() + "&to=" + to.toString());
}
getResources(): Observable<any[]> {
// simulating an HTTP request
return new Observable(observer => {
setTimeout(() => {
observer.next(this.resources);
}, 200);
});
// return this.http.get("/api/resources");
}
}
Package.json
The package.json
file includes the standard dependencies as they were generated by Angular 18 CLI and also the daypilot-pro-angular
package that is hosted at npm.daypilot.org.
{
"name": "angular18-scheduler",
"version": "0.0.0",
"license": "SEE LICENSE IN license/LicenseAgreementTrial.pdf",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^18.0.0",
"@angular/common": "^18.0.0",
"@angular/compiler": "^18.0.0",
"@angular/core": "^18.0.0",
"@angular/forms": "^18.0.0",
"@angular/platform-browser": "^18.0.0",
"@angular/platform-browser-dynamic": "^18.0.0",
"@angular/router": "^18.0.0",
"daypilot-pro-angular": "https://npm.daypilot.org/daypilot-pro-angular/trial/2024.2.5951.tar.gz",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.14.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "^18.0.1",
"@angular/cli": "^18.0.1",
"@angular/compiler-cli": "^18.0.0",
"@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"typescript": "~5.4.2"
}
}