Overview

  • Learn how to filter events in real time using the specified text in the weekly Angular calendar.

  • You can also filter events by type (“reservation”, “maintenance”).

  • Both filters can be combined and applied at once.

  • Includes a trial version of DayPilot Pro for JavaScript (see License below).

This tutorial focuses on the Event Filtering feature. For an introductory tutorial on the Angular Calendar component, please see the Angular Calendar: Day/Week/Month Views (Open-Source) 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. Buy a license.

Filtering Events By Name in Angular Calendar

FIlter Events by Text in the Angular Calendar Component

In this example, we will add a text input control above the Calendar. It will detect text changes using the input event and apply the filter to the Calendar component.

HTML template:

<input [(ngModel)]="filterText" type="text" placeholder="Filter" (input)="filter()">

The current value of the input field is stored in the filterText property:

filterText: string = "";

As the user types the filter text, our component calls the filter() method to filter the events:

filter(): void {
  const params = {
    text: this.filterText,
  };
  this.calendar.control.events.filter(params);
}

This method creates a filter parameters object and applies the filter by calling the events.filter() method.

When the filter is applied, the Calendar component calls the onEventFilter event handler for every event to evaluate whether it should be displayed or not, depending on the parameters.

Our implementation will hide events that don’t contain the specified text. It converts the filter text and the event text to uppercase to make the filter case-insensitive.

onEventFilter: (args) => {
  const filterText = args.filterParam.text || "";
  const eventText = args.e.text() || "";
  const textMatches = eventText.toUpperCase().indexOf(filterText.toUpperCase()) !== -1;

  if (!textMatches) {
    args.visible = false;
  }
},

Filtering Events by Type in Angular Calendar

FIlter Events by Type in the Angular Calendar Component

The same approach can be used when filtering Calendar events by type.

We will add a drop-down list with events types to the toolbar:

<select [(ngModel)]="filterType" (change)="filter()">
  <option value="all">All</option>
  <option value="reservation">Reservation</option>
  <option value="maintenance">Maintenance</option>
</select>

The selected values is available using the filterType property:

filterType: string = "all";

The filter() method will store the selected value in the type property of the filter params and call events.filter():

filter(): void {
  const params = {
    type: this.filterType
  };
  this.calendar.control.events.filter(params);
}

The onEventFilter event handler checks whether the event type corresponds to the selected value and hides other event types:

onEventFilter: (args) => {
  const filterType = args.filterParam.type || "all";
  const eventType = args.e.data.type || "";
  const typeMatches = filterType === "all" || filterType === eventType;

  if (!typeMatches) {
    args.visible = false;
  }

},

Using a Complex Event Filter

Using a Complex Event Filter in the Angular Calendar Component

In this step, we will modify our Angular app to apply both rules at once.

The filter() method needs to set both criteriea:

filter(): void {
  const params = {
    text: this.filterText,
    type: this.filterType
  };
  this.calendar.control.events.filter(params);
}

And the onEventFilter event handler checks both rules. If any of them doesn’t match, the event is marked as hidden:

onEventFilter: (args) => {
  const filterText = args.filterParam.text || "";
  const eventText = args.e.text() || "";
  const textMatches = eventText.toUpperCase().indexOf(filterText.toUpperCase()) !== -1;

  const filterType = args.filterParam.type || "all";
  const eventType = args.e.data.type || "";
  const typeMatches = filterType === "all" || filterType === eventType;

  if (!textMatches) {
    args.visible = false;
  }
  if (!typeMatches) {
    args.visible = false;
  }

},

Clearing the Calendar Event Filter

To clear the filter, it is necessary to call the events.filter() method with a null parameter (or without a parameter). This will make the Calendar component display all events.

Our clearFilter() method also resets the filter input controls:

clearFilter(): void {
  this.calendar.control.events.filter(null);
  this.filterText = "";
  this.filterType = "all";
}

Full Source Code

Here is the full source code of out Angular Calendar app the allows filtering events using the specified text and event type.

The calendar.component.ts file defines the weekly Calendar UI and toolbar with filtering options. It implements the filtering rules:

import {Component, ViewChild, AfterViewInit} from "@angular/core";
import {DayPilot, DayPilotModule, DayPilotCalendarComponent} from "daypilot-pro-angular";
import {DataService} from "./data.service";
import {FormsModule} from "@angular/forms";

@Component({
  selector: 'calendar-component',
  standalone: true,
  imports: [DayPilotModule, FormsModule],
  providers: [DataService],
  template: `
    <div class="toolbar">
      <input [(ngModel)]="filterText" type="text" placeholder="Filter" (input)="filter()">
      <select [(ngModel)]="filterType" (change)="filter()">
        <option value="all">All</option>
        <option value="reservation">Reservation</option>
        <option value="maintenance">Maintenance</option>
      </select>
      <button (click)="clearFilter()">Clear</button>
    </div>
    <daypilot-calendar [config]="config" [events]="events" #calendar></daypilot-calendar>
  `,
  styles: [``]
})
export class CalendarComponent implements AfterViewInit {

  @ViewChild("calendar")
  calendar!: DayPilotCalendarComponent;

  filterText: string = "";

  filterType: string = "all";

  events: any[] = [];

  config: DayPilot.CalendarConfig = {
    viewType: "Week",
    timeRangeSelectedHandling: "Enabled",
    onTimeRangeSelected: async (args) => {
      const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1");
      const calendar = args.control;
      calendar.clearSelection();
      if (modal.canceled) { return; }
      calendar.events.add({
        start: args.start,
        end: args.end,
        id: DayPilot.guid(),
        text: modal.result
      });
    },
    onEventFilter: (args) => {
      const filterText = args.filterParam.text || "";
      const eventText = args.e.text() || "";
      const textMatches = eventText.toUpperCase().indexOf(filterText.toUpperCase()) !== -1;

      const filterType = args.filterParam.type || "all";
      const eventType = args.e.data.type || "";
      const typeMatches = filterType === "all" || filterType === eventType;

      if (!textMatches) {
        args.visible = false;
      }
      if (!typeMatches) {
        args.visible = false;
      }

    },
    onBeforeEventRender: args => {
      const isMaintenance = args.data["type"] === "maintenance";
      const orange = "#f39c12";
      const green = "#6aa84f";
      args.data.backColor = isMaintenance ? orange : green;
      args.data.borderColor = "darker";
      args.data.fontColor = "#ffffff";
      args.data.barHidden = true;
      args.data.borderRadius = 15;
      if (isMaintenance) {
        const text = args.data.text;
        args.data.html = `<div style='font-weight:bold;'>Maintenance</div><div>${text}</div>`;
      }
    }
  };

  constructor(private ds: DataService) {
  }

  filter(): void {
    const params = {
      text: this.filterText,
      type: this.filterType
    };
    this.calendar.control.events.filter(params);
  }

  clearFilter(): void {
    this.calendar.control.events.filter(null);
    this.filterText = "";
  }

  ngAfterViewInit(): void {
    const from = this.calendar.control.visibleStart();
    const to = this.calendar.control.visibleEnd();
    this.ds.getEvents(from, to).subscribe(result => {
      this.events = result;
    });
  }

}

The data.service.ts generates some sample events that will be displayed in the Calendar component.

import {Injectable} from "@angular/core";
import {Observable} from "rxjs";
import {DayPilot} from "daypilot-pro-angular";
import {HttpClient} from "@angular/common/http";

@Injectable()
export class DataService {

  events: any[] = [
    {
      id: 1,
      start: DayPilot.Date.today().firstDayOfWeek().addHours(10),
      end: DayPilot.Date.today().firstDayOfWeek().addHours(12),
      text: "Event 1",
      type: "reservation"
    },
    {
      id: 2,
      start: DayPilot.Date.today().firstDayOfWeek().addDays(1).addHours(12),
      end: DayPilot.Date.today().firstDayOfWeek().addDays(1).addHours(16),
      text: "Event 2",
      type: "maintenance"
    },
    {
      id: 3,
      start: DayPilot.Date.today().firstDayOfWeek().addDays(1).addHours(10),
      end: DayPilot.Date.today().firstDayOfWeek().addDays(1).addHours(11),
      text: "Event 3",
      type: "reservation"
    },
    {
      id: 4,
      start: DayPilot.Date.today().firstDayOfWeek().addDays(2).addHours(10),
      end: DayPilot.Date.today().firstDayOfWeek().addDays(2).addHours(15),
      text: "Event 4",
      type: "reservation"
    }
  ];

  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());
  }

}