Features
Angular Scheduler component with resources on the Y (vertical) axis and time on the X (horizontal) axis
Instant event filtering: by text, category and event duration
Includes a trial version of DayPilot Pro for JavaScript
This tutorial doesn't include Angular Scheduler basics which are covered in the following tutorial:
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.
Filtering Events by Text
As the first step, we will add a text input box which lets users filter events by content. The search box will be displayed above the Scheduler control. The <input>
element specifies the source using [ngModel]
- you can use it to set the initial value. It's also required for ngModelChange
event handler - without [ngModel]
the event won't fire.
Filter: <input type="text" [ngModel]="filter.text" (ngModelChange)="changeText($event)" />
The event handler fires changeText()
method whenever the <input>
content is updated. This method stores the new value in the filter
object (as filter.text
) and requests a Scheduler refresh using events.filter() call.
export class SchedulerComponent implements AfterViewInit {
filter: DayPilot.SchedulerConfig = {
text: ""
};
// ...
changeText(val: string) {
this.filter.text = val;
this.applyFilter();
}
applyFilter() {
this.scheduler.control.events.filter(this.filter);
}
}
Whenever the events.filter()
method is called the Scheduler calls onEventFilter event handler for every event to decide whether it meets the filtering condition. You need to provide custom onEventFilter
handler.
Our implementation converts both the supplied text (args.filter.text
) and the event text (args.e.text()
) to lowercase to provide case-insensitive search. If the event text doesn't include the search text it is marked as not visible (args.visible
).
export class SchedulerComponent implements AfterViewInit {
config: DayPilot.SchedulerConfig = {
// ...
onEventFilter: args => {
const params = args.filterParam;
if (params.text && args.e.text().toLowerCase().indexOf(params.text.toLowerCase()) < 0) {
args.visible = false;
}
}
};
// ...
}
All elements integrated (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: `
<div class="space">
Filter: <input type="text" [ngModel]="filter.text" (ngModelChange)="changeText($event)" />
...
</div>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler!: DayPilotSchedulerComponent;
events: any[] = [];
filter: any = {
text: ""
};
config: DayPilot.SchedulerConfig = {
// ...
onEventFilter: args => {
const params = args.filterParam;
if (params.text && args.e.text().toLowerCase().indexOf(params.text.toLowerCase()) < 0) {
args.visible = false;
}
}
};
// ...
changeText(val: string) {
this.filter.text = val;
this.applyFilter();
}
applyFilter() {
this.scheduler.control.events.filter(this.filter);
}
}
Filtering Events by Category
A similar approach is used for filtering by category.
The possible category values are displayed using a drop-down list (<select>
element). Every dropdown change triggers changeCategory()
method which updates the filter object and requests a Scheduler refresh.
The onEventFilter
event handler compares the event category (available as args.e.data.category
) with the selected value. If they don't match (and the selected value isn't "any"
) the event is hidden using args.visible = false
.
import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="space">
...
Category: <select (ngModelChange)="changeCategory($event)" [ngModel]="filter.category">
<option *ngFor="let cat of categories" [ngValue]="cat.id">{{cat.name}}</option>
</select>
...
</div>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler!: DayPilotSchedulerComponent;
events: any[] = [];
categories: any[] = [
{ id: "any", name: "Any"},
{ id: "cat1", name: "Marketing"},
{ id: "cat2", name: "Development"},
{ id: "cat3", name: "Sales"}
];
filter: any = {
category: "any"
};
config: DayPilot.SchedulerConfig = {
// ...
onEventFilter: args => {
const params = args.filterParam;
if (params.category !== "any" && args.e.data.category !== params.category) {
args.visible = false;
}
}
};
changeCategory(val: string) {
this.filter.category = val;
this.applyFilter();
}
applyFilter() {
this.scheduler.control.events.filter(this.filter);
}
// ...
}
The event category is provided in the event data object in category
field. This is a sample data set:
events: any[] = [
{
id: "1",
resource: "R1",
start: "2025-07-03",
end: "2025-07-10",
text: "Prepare Web Site",
category: "cat1"
},
{
id: "2",
resource: "R2",
start: "2025-07-02",
end: "2025-07-07",
text: "Implement New Features",
category: "cat2"
},
{
id: "3",
resource: "R2",
start: "2025-07-08",
end: "2025-07-10",
text: "Launch",
category: "cat1"
},
{
id: "4",
resource: "R1",
start: "2025-07-11",
end: "2025-07-15",
text: "Contact Prospects",
category: "cat3"
}
];
Filtering Events by Duration
The event duration filter checks whether the event takes more than 2 days by comparing args.e.duration()
with DayPilot.Duration.ofDays(2)
. Events that take longer are hidden.
import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="space">
...
<label for="shortonly"><input type="checkbox" id="shortonly" [ngModel]="filter.shortOnly" (ngModelChange)="changeShort($event)"> Short Events Only</label>
...
</div>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler!: DayPilotSchedulerComponent;
events: any[] = [];
filter: any = {
shortOnly: false
};
config: DayPilot.SchedulerConfig = {
// ...
onEventFilter: args => {
const params = args.filterParam;
if (params.shortOnly && args.e.duration() > DayPilot.Duration.ofDays(2)) {
args.visible = false;
}
}
};
changeShort(val: string) {
this.filter.shortOnly = val;
this.applyFilter();
}
applyFilter() {
this.scheduler.control.events.filter(this.filter);
}
// ...
}
Complex Event Filter (and Filter Clearing)
Finally, we integrate all three filter types. In order to be visible in the Scheduler, the event must match all three conditions (text, category, duration).
We'll also add a "Clear" button which resets all filter parameters and displays all events.
import {AfterViewInit, Component, ViewChild} from "@angular/core";
import {DayPilot, DayPilotSchedulerComponent} from "daypilot-pro-angular";
import {DataService, EventData} from "./data.service";
@Component({
selector: 'scheduler-component',
template: `
<div class="toolbar">
<span class="toolbar-item">
Filter: <input type="text" [ngModel]="filter.text" (ngModelChange)="changeText($event)" />
</span>
<span class="toolbar-item">
Category:
<select (ngModelChange)="changeCategory($event)" [ngModel]="filter.category">
<option *ngFor="let cat of categories" [ngValue]="cat.id">{{cat.name}}</option>
</select>
</span>
<span class="toolbar-item">
<label for="shortonly"><input type="checkbox" id="shortonly" [ngModel]="filter.shortOnly" (ngModelChange)="changeShort($event)"> Short Events Only</label>
</span>
<span class="toolbar-item">
<a href="" (click)="clearFilter()">Clear</a>
</span>
</div>
<daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
`,
styles: [``]
})
export class SchedulerComponent implements AfterViewInit {
@ViewChild("scheduler") scheduler!: DayPilotSchedulerComponent;
events: EventData[] = [];
categories: any[] = [
{ id: "any", name: "Any"},
{ id: "cat1", name: "Marketing"},
{ id: "cat2", name: "Development"},
{ id: "cat3", name: "Sales"}
];
filter: any = {
category: "any",
text: "",
shortOnly: false
};
config: DayPilot.SchedulerConfig = {
timeHeaders : [
{groupBy: "Month", format: "MMMM yyyy"},
{groupBy: "Day", format: "d"}
],
eventHeight: 60,
cellWidth: 70,
rowMarginTop: 5,
rowMarginBottom: 5,
scale: "Day",
days: 31,
startDate: "2025-07-01",
onBeforeEventRender: args => {
const categoryId = (<any>args.data).category;
switch (categoryId) {
case "cat1":
args.data.barColor = "#45818e";
break;
case "cat2":
args.data.barColor = "#f1c232";
break;
case "cat3":
args.data.barColor = "#6aa84f";
break;
}
const category = this.categories.find(c => c.id == categoryId);
if (category) {
args.data.areas = [
{ top: 5, right: 3, html: category.name, style: "color: " + args.data.barColor}
];
}
},
onEventFilter: args => {
const params = args.filterParam;
if (params.text && args.e.text().toLowerCase().indexOf(params.text.toLowerCase()) < 0) {
args.visible = false;
}
if (params.category !== "any" && args.e.data.category !== params.category) {
args.visible = false;
}
if (params.shortOnly && args.e.duration() > DayPilot.Duration.ofDays(2)) {
args.visible = false;
}
}
};
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;
});
}
changeText(val: string) {
this.filter.text = val;
this.applyFilter();
}
changeCategory(val: string) {
this.filter.category = val;
this.applyFilter();
}
changeShort(val: string) {
this.filter.shortOnly = val;
this.applyFilter();
}
clearFilter() {
this.filter.category = "any";
this.filter.text = "";
this.filter.shortOnly = false;
this.applyFilter();
return false;
}
applyFilter() {
this.scheduler.control.events.filter(this.filter);
}
}