Overview
The active areas feature of the Angular Scheduler component allows adding different types of action buttons to the Scheduler row header columns.
In this tutorial, we explore the following options:
context menu that is activated using a hover icon
hyperlink-like button with custom text
custom action icons
In addition to the active areas, it is also possible to add custom Angular components to the Scheduler row headers:
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.
Context Menu Triggered by Active Area
The first example uses a hover active area (visibility: "Hover"
) to show a button that activates a context menu:
The active area is added to the first row header column using onBeforeHeaderRender event handler.
scheduler.component.ts
onBeforeRowHeaderRender: args => {
args.row.columns[0].areas = [
{
right: 5,
top: 8,
height: 20,
width: 20,
padding: 2,
visibility: "Hover",
backColor: "#666666",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#threedots-v",
action: "ContextMenu",
menu: this.rowMenu,
style: "cursor: pointer; border-radius: 50%;"
}
];
// ...
}
This active area displays the “vertical three dots” icon from the daypilot.svg
icon bundle.
Context menu definition:
rowMenu: DayPilot.Menu = new DayPilot.Menu({
items: [
{
text: "Open",
onClick: args => {
const row = args.source;
DayPilot.Modal.alert("Opening: " + row.data.myData);
}
},
{
text: "Delete",
onClick: async args => {
const row = args.source;
const modal = await DayPilot.Modal.confirm("Do you want to delete this row? " + row.data.myData);
this.scheduler.control.rows.remove(row);
}
}
]
});
The onClick
event handler of the “Open” menu items shows a simple modal dialog with custom row data.
The “Delete” menu item asks for a confirmation and deletes the row from the Scheduler using the rows.remove() method.
Hyperlink Button
Another type of active area adds a custom text that is styled as a hyperlink.
The onClick
event handler of the active area lets you specify the click action. You can use it to call Angular methods available in your component.
onBeforeRowHeaderRender: args => {
// ...
if (args.row.columns[1]) {
args.row.columns[1].areas = [
{
left: 0,
right: 0,
top: 0,
bottom: 0,
html: "Details...",
verticalAlignment: "center",
horizontalAlignment: "center",
style: "cursor: pointer; text-decoration: underline; color: #cc0000;",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a row with the following data: " + row.data.myData);
}
}
];
}
}
Multiple Action Icons in a Cell
The last column displays three icons with different colors and custom actions.
onBeforeRowHeaderRender: args => {
// ...
if (args.row.columns[2]) {
args.row.columns[2].areas = [
{
left: 5,
top: 8,
width: 20,
height: 20,
backColor: "#3498db",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#plus-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Blye",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a blue icon: " + row.data.myData);
}
},
{
left: 30,
top: 8,
width: 20,
height: 20,
backColor: "#2ecc71",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#minichevron-down-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Green",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a green icon: " + row.data.myData);
}
},
{
left: 55,
top: 8,
width: 20,
height: 20,
backColor: "#ffd551",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#x-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Yellow",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a yellow icon: " + row.data.myData);
}
},
];
}
}
Full Source Code
Here is the full source code of our Angular Scheduler component configured to display different types of action icons, buttons, and hyperlinks in the row headers (scheduler.component.ts
);
import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilot, DayPilotModule, 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[] = [];
rowMenu: DayPilot.Menu = new DayPilot.Menu({
items: [
{
text: "Open",
onClick: args => {
const row = args.source;
DayPilot.Modal.alert("Opening: " + row.data.myData);
}
},
{ text: "Delete",
onClick: async args => {
const row = args.source;
const modal = await DayPilot.Modal.confirm("Do you want to delete this row? " + row.data.myData);
this.scheduler.control.rows.remove(row);
}
}
]
});
config: DayPilot.SchedulerConfig = {
timeHeaders: [{groupBy: "Month"},{groupBy: "Day", format: "d"}],
scale: "Day",
days: DayPilot.Date.today().daysInMonth(),
startDate: DayPilot.Date.today().firstDayOfMonth(),
timeRangeSelectedHandling: "Enabled",
onTimeRangeSelected: async (args) => {
const scheduler = args.control;
const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
scheduler.clearSelection();
if (modal.canceled) { return; }
scheduler.events.add({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result
});
},
rowHeaderColumns: [
{ text: "Name", width: 140 },
{ text: "Click" },
{ text: "Actions"}
],
treeEnabled: true,
onBeforeRowHeaderRender: args=> {
args.row.columns[0].areas = [
{
right: 5,
top: 8,
height: 20,
width: 20,
padding: 2,
visibility: "Hover",
backColor: "#666666",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#threedots-v",
action: "ContextMenu",
menu: this.rowMenu,
style: "cursor: pointer; border-radius: 50%;"
}
];
if (args.row.columns[1]) {
args.row.columns[1].areas = [
{
left: 0,
right: 0,
top: 0,
bottom: 0,
html: "Details...",
verticalAlignment: "center",
horizontalAlignment: "center",
style: "cursor: pointer; text-decoration: underline; color: #cc0000;",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a row with the following data: " + row.data.myData);
}
}
];
}
if (args.row.columns[2]) {
args.row.columns[2].areas = [
{
left: 5,
top: 8,
width: 20,
height: 20,
backColor: "#3498db",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#plus-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Blye",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a blue icon: " + row.data.myData);
}
},
{
left: 30,
top: 8,
width: 20,
height: 20,
backColor: "#2ecc71",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#minichevron-down-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Green",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a green icon: " + row.data.myData);
}
},
{
left: 55,
top: 8,
width: 20,
height: 20,
backColor: "#ffd551",
fontColor: "#ffffff",
symbol: "/icons/daypilot.svg#x-2",
padding: 2,
style: "cursor: pointer; border-radius: 50%;",
toolTip: "Yellow",
onClick: (clickArgs: any) => {
const row = clickArgs.source;
DayPilot.Modal.alert("You clicked a yellow icon: " + row.data.myData);
}
},
];
}
}
};
constructor(private ds: DataService) {
}
ngAfterViewInit(): void {
this.ds.getResources().subscribe(result => this.config.resources = result);
const from = this.scheduler.control.visibleStart();
const to = this.scheduler.control.visibleEnd();
this.ds.getEvents(from, to).subscribe(result => {
this.events = result;
});
}
}
The DataService
class loads sample data. Note that the items of the resources
array contain a custom data field (myData
).
You can find the source code in the data.service.ts
file:
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', myData: "Group A Details", expanded: true, children: [
{name: 'Resource 1', id: 'R1', myData: "Resource 1 Details"},
{name: 'Resource 2', id: 'R2', myData: "Resource 2 Details"},
{name: 'Resource 3', id: 'R3', myData: "Resource 3 Details"},
{name: 'Resource 4', id: 'R4', myData: "Resource 4 Details"}
]
},
{
name: 'Group B', id: 'GB', myData: "Group B Details", expanded: true, children: [
{name: 'Resource 5', id: 'R5', myData: "Resource 5 Details"},
{name: 'Resource 6', id: 'R6', myData: "Resource 6 Details"},
{name: 'Resource 7', id: 'R7', myData: "Resource 7 Details"},
{name: 'Resource 8', id: 'R8', myData: "Resource 8 Details"}
]
}
];
events: DayPilot.EventData[] = [
{
id: '1',
resource: 'R1',
start: '2025-10-03',
end: '2025-10-08',
text: 'Scheduler Event 1',
barColor: '#e69138'
},
{
id: '2',
resource: 'R3',
start: '2025-10-02',
end: '2025-10-05',
text: 'Scheduler Event 2',
barColor: '#6aa84f'
},
{
id: '3',
resource: 'R3',
start: '2025-10-06',
end: '2025-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");
}
}
To download the complete Angular project, please see the link at the top of the tutorial.