Features
Angular Scheduler component
Dynamic modification of event context menu (menu for events starting in the past have disabled “Delete” menu item)
Dynamic modification of row header context menu (different menu items for parent/child nodes)
Angular 18 project generated using Scheduler UI Builder
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.
Event Context Menu
The event context menu is defined using the contextMenu property of the config
object.
Our example menu has a “Delete” item that removes the selected event from the Angular Scheduler UI and four items for changing the event color (blue, green, yellow, red).
config: DayPilot.SchedulerConfig = {
contextMenu: new DayPilot.Menu({
items: [
{ text: "Delete", onClick: (args) => { this.scheduler.control.events.remove(args.source); } },
{ text: "-"},
{
text: "Blue",
icon: "icon icon-blue",
tags: { color: "#1155cc" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Green",
icon: "icon icon-green",
tags: { color: "#6aa84f" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Yellow",
icon: "icon icon-yellow",
tags: { color: "#f1c232" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Red",
icon: "icon icon-red",
tags: { color: "#cc0000" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
],
onShow: args => {
let e = args.source;
// disable deleting for events that start in the past
if (e.start() < DayPilot.Date.today()) {
args.menu.items[0].disabled = true;
}
else {
args.menu.items[0].disabled = false;
}
}
}),
// ...
};
The updateColor
method changes the bar color of the selected Scheduler event:
updateColor(e: DayPilot.Event, color: string): void {
e.data.barColor = color;
this.scheduler.control.events.update(e);
}
Dynamic Modification of the Event Context Menu
You can modify the context menu properties upon invocation by handling the onShow event handler.
This event handler checks the event start date. If the event starts before today, the first menu item ("Delete" action) is disabled.
config: DayPilot.SchedulerConfig = {
contextMenu: new DayPilot.Menu({
items: [
{ text: "Delete", onClick: (args) => { this.scheduler.control.events.remove(args.source); } },
// ...
],
onShow: args => {
let e = args.source;
// disable deleting for events that start in the past
if (e.start() < DayPilot.Date.today()) {
args.menu.items[0].disabled = true;
}
else {
args.menu.items[0].disabled = false;
}
}
}),
// ...
}
Dynamic Row Header Context Menu
The same method can be used to customize the row header context menu depending on the row. This example displays a different menu for resource groups and resources.
Context menu for parent rows (groups):
Context menu for resources (rows without children):
In this example, we have defined two different menu item arrays. We use the onShow event handler to set the items property as needed.
The implementation of the “Details” menu item is different for each row type:
The group details modal dialog contains only the group name.
The resource details modal dialog lets you edit the resource name and capacity.
config: DayPilot.SchedulerConfig = {
contextMenuResource: new DayPilot.Menu({
onShow: args => {
let hasChildren = args.source.children().length > 0;
if (hasChildren) {
args.menu.items = this.menuItemsGroup;
}
else {
args.menu.items = this.menuItemsResource;
}
}
})
}
menuItemsGroup: DayPilot.MenuItemData[] = [
{
text: "Group Details",
onClick: async args => {
const form = [
{name: "Name", id: "name"},
];
const row = args.source;
const modal = await DayPilot.Modal.form(form, row.data);
if (modal.canceled) {
return;
}
this.scheduler.control.rows.update(modal.result);
}
}
];
menuItemsResource: DayPilot.MenuItemData[] = [
{
text: "Resource Details",
onClick: async args => {
const form = [
{name: "Name", id: "name"},
{name: "Capacity", id: "capacity"},
];
const row = args.source;
const modal = await DayPilot.Modal.form(form, row.data);
if (modal.canceled) {
return;
}
this.scheduler.control.rows.update(modal.result);
}
}
];
Source Code
Here is the full source code of the customized Angular Scheduler component that uses dynamically-modified context menus (scheduler.component.ts
):
import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";{}
@Component({
selector: 'scheduler-component',
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"}
],
rowHeaderColumns: [
{title: "Name"},
{title: "Capacity", display: "capacity"}
],
scale: "Day",
days: 31,
startDate: "2024-07-01",
treeEnabled: true,
separators: [
{color: "red", location: DayPilot.Date.today() }
],
onTimeRangeSelected: async (args) => {
const dp = args.control;
const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
dp.clearSelection();
if (!modal.result) { return; }
dp.events.add({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result
});
},
contextMenu: new DayPilot.Menu({
items: [
{ text: "Delete", onClick: (args) => { this.scheduler.control.events.remove(args.source); } },
{ text: "-"},
{
text: "Blue",
icon: "icon icon-blue",
tags: { color: "#1155cc" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Green",
icon: "icon icon-green",
tags: { color: "#6aa84f" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Yellow",
icon: "icon icon-yellow",
tags: { color: "#f1c232" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
{
text: "Red",
icon: "icon icon-red",
tags: { color: "#cc0000" },
onClick: args => { this.updateColor(args.source, args.item.tags.color); }
},
],
onShow: args => {
let e = args.source;
// disable deleting for events that start in the past
if (e.start() < DayPilot.Date.today()) {
// @ts-ignore
args.menu.items[0].disabled = true;
}
else {
// @ts-ignore
args.menu.items[0].disabled = false;
}
}
}),
contextMenuResource: new DayPilot.Menu({
onShow: args => {
let hasChildren = args.source.children().length > 0;
if (hasChildren) {
args.menu.items = this.menuItemsGroup;
}
else {
args.menu.items = this.menuItemsResource;
}
}
})
};
menuItemsGroup: DayPilot.MenuItemData[] = [
{
text: "Group Details",
onClick: async args => {
const form = [
{name: "Name", id: "name"},
];
const row = args.source;
const modal = await DayPilot.Modal.form(form, row.data);
if (modal.canceled) {
return;
}
this.scheduler.control.rows.update(modal.result);
}
}
];
menuItemsResource: DayPilot.MenuItemData[] = [
{
text: "Resource Details",
onClick: async args => {
const form = [
{name: "Name", id: "name"},
{name: "Capacity", id: "capacity"},
];
const row = args.source;
const modal = await DayPilot.Modal.form(form, row.data);
if (modal.canceled) {
return;
}
this.scheduler.control.rows.update(modal.result);
}
}
];
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;
});
}
updateColor(e: DayPilot.Event, color: string): void {
e.data.barColor = color;
this.scheduler.control.events.update(e);
}
}