Overview
The active areas feature of the Angular Scheduler component allows adding different types of action buttons to the Scheduler row header columns:
context menu that is activated using a hover icon
hyperlink-like button with custom text
custom actions icons
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 = [
{
width: 15,
right: 5,
top: 5,
height: 15,
visibility: "Hover",
backColor: "#fff",
html: "...",
action: "ContextMenu",
contextMenu: this.rowMenu,
style: "cursor: pointer; border: 1px solid #ccc; text-align: center;"
}
];
// ...
}
Context menu definition:
rowMenu: DayPilot.Menu = new DayPilot.Menu({
items: [
{ text: "Open"},
{ text: "Delete", onClick: args => {
let row = args.source;
alert("Deleting: " + row.data.myData);
}
}
]
});
You can call Angular methods from onClick
event handler of the menu item.
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=> {
args.row.columns[1].areas = [
{
left: 0,
right: 0,
top: 0,
bottom: 0,
html: "Click me",
style: "cursor: pointer; text-decoration: underline; display: flex; align-items: center; justify-content: center; color: #cc0000;",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a row with the following data: " + row.data.myData);
}
}
];
}
Multiple Action Icons in a Cell
The last column displays three color icons with different onClick
event handlers.
onBeforeRowHeaderRender: args=> {
args.row.columns[1].areas = [
{
left: 10,
top: 10,
width: 15,
height: 15,
backColor: "#f1c232",
// backColor: "#cc0000",
style: "cursor: pointer; border: 1px solid #bf9000; box-sizing: border-box;",
toolTip: "Yellow",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a yellow icon: " + row.data.myData);
}
},
{
left: 30,
top: 10,
width: 15,
height: 15,
backColor: "#6aa84f",
style: "cursor: pointer; border: 1px solid #38761d; box-sizing: border-box;",
toolTip: "Green",
onClick: clickArgs => {
let row = clickArgs.source;
alert("You clicked a green icon: " + row.data.myData);
}
},
{
left: 50,
top: 10,
width: 15,
height: 15,
backColor: "#3c78d8",
style: "cursor: pointer; border: 1px solid #1155cc; box-sizing: border-box;",
toolTip: "Blue",
onClick: clickArgs => {
let row = clickArgs.source;
alert("You clicked a blue icon: " + row.data.myData);
}
},
];
}
Full Source Code
scheduler.component.ts
import {AfterViewInit, Component, ViewChild} 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', {static: false})
scheduler!: DayPilotSchedulerComponent;
events: any[] = [];
rowMenu: DayPilot.Menu = new DayPilot.Menu({
items: [
{ text: "Open"},
{ text: "Delete", onClick: args => {
let row = args.source;
alert("Deleting: " + row.data.myData);
}
}
]
});
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: function (args) {
var dp = args.control;
DayPilot.Modal.prompt("Create a new event:", "Event 1").then(function(modal) {
dp.clearSelection();
if (!modal.result) { return; }
dp.events.add(new DayPilot.Event({
start: args.start,
end: args.end,
id: DayPilot.guid(),
resource: args.resource,
text: modal.result
}));
});
},
rowHeaderColumns: [
{ text: "Name" },
{ text: "Click" },
{ text: "Actions"}
],
treeEnabled: true,
onBeforeRowHeaderRender: args=> {
args.row.columns[0].areas = [
{
width: 15,
right: 5,
top: 5,
height: 15,
visibility: "Hover",
backColor: "#fff",
html: "...",
action: "ContextMenu",
contextMenu: this.rowMenu,
style: "cursor: pointer; border: 1px solid #ccc; text-align: center;"
}
];
args.row.columns[1].areas = [
{
left: 0,
right: 0,
top: 0,
bottom: 0,
html: "Click me",
style: "cursor: pointer; text-decoration: underline; display: flex; align-items: center; color: #cc0000; box-sizing: border-box; padding: 2px;",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a row with the following data: " + row.data.myData);
}
}
];
args.row.columns[2].areas = [
{
left: 10,
top: 10,
width: 15,
height: 15,
backColor: "#f1c232",
// backColor: "#cc0000",
style: "cursor: pointer; border: 1px solid #bf9000; box-sizing: border-box;",
toolTip: "Yellow",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a yellow icon: " + row.data.myData);
}
},
{
left: 30,
top: 10,
width: 15,
height: 15,
backColor: "#6aa84f",
style: "cursor: pointer; border: 1px solid #38761d; box-sizing: border-box;",
toolTip: "Green",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a green icon: " + row.data.myData);
}
},
{
left: 50,
top: 10,
width: 15,
height: 15,
backColor: "#3c78d8",
style: "cursor: pointer; border: 1px solid #1155cc; box-sizing: border-box;",
toolTip: "Blue",
onClick: (clickArgs: any) => {
let row = clickArgs.source;
alert("You clicked a blue 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;
});
}
}
data.service.ts
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: any[] = [
{ name: 'Group A', id: 'GA', myData: "GA-value" , expanded: true, children: [
{ name: 'Resource 1', id: 'R1', myData: "R1-value" },
{ name: 'Resource 2', id: 'R2', myData: "R2-value" }
]},
{ name: 'Group B', id: 'GB', myData: "GB-value" , expanded: true, children: [
{ name: 'Resource 3', id: 'R3', myData: "R3-value" , unavailable: true},
{ name: 'Resource 4', id: 'R4', myData: "R4-value" }
]}
];
events: any[] = [
{
id: '1',
resource: 'R1',
start: '2021-05-03',
end: '2021-05-08',
text: 'Scheduler Event 1',
color: '#e69138'
},
{
id: '2',
resource: 'R2',
start: '2021-05-02',
end: '2021-05-05',
text: 'Scheduler Event 2',
color: '#6aa84f'
},
{
id: '3',
resource: 'R2',
start: '2021-05-06',
end: '2021-05-09',
text: 'Scheduler Event 3',
color: '#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");
}
}