Overview

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.

Setup

Install DayPilot Pro:

npm install https://npm.daypilot.org/daypilot-pro-angular/trial/2025.1.6423.tar.gz

Install ExcelJS:

npm install exceljs

ExcelJS is used by the Scheduler to generate the Excel XLSX file.

It is necessary to pass the refererence to the ExcelJS object to the Scheduler using the exceljs property:

import {DayPilot, DayPilotModule, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import ExcelJS from 'exceljs';
// ...

@Component({
  selector: 'scheduler-component',
  standalone: true,
  imports: [DayPilotModule, FormsModule],
  providers: [DataService],
  template: `
    <daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
  `,
  styles: [``]
})
export class SchedulerComponent implements AfterViewInit {

  // ...

  config: DayPilot.SchedulerConfig = {
    // ...
    exceljs: ExcelJS,
    // ...
  };

}

Now it is possible to export the visual representation of the Scheduler component to an Excel file using the exportAs() method.

Frozen Headers in the Exported Excel Spreadsheet

Angular Scheduler - Export to Excel Spreadsheet with Frozen Headers

When you set the Scheduler export area to "full", the Scheduler freezes the headers (both vertical and horizontal) in the output spreadsheet.

exportToExcel(): void {
  const options = {
    area: "full"
  };
  this.scheduler.control.exportAs("xlsx", options).download(this.filename || "scheduler.xlsx");
}

Since version 2025.1.5423, the Scheduler automatically sets the top-level corner of the standard to the top-left cell of the current viewport displayed in the browser.

Add Rows to the Frozen Headers

Angular Scheduler - Add Rows to the Frozen Headers in XLSX

The Angular Scheduler component supports freezing select rows (representing resources) at the top or bottom of the grid.

The rows frozen at the top will be included in the frozen header in the exported XLSX file as well.

In our Angular project, we define a special frozen row that will display the utilization summary:

resources: DayPilot.ResourceData[] = [
  {
    name: "Utilization", id: "summary", frozen: "top", cellsAutoUpdated: true
  },
  {
    name: 'Group A', id: 'GA', expanded: true, children: [
      {name: 'Resource 1', id: 'R1', capacity: 10},
      {name: 'Resource 2', id: 'R2', capacity: 30},
      {name: 'Resource 3', id: 'R3', capacity: 20},
      {name: 'Resource 4', id: 'R4', capacity: 40}
    ]
  },
  {
    name: 'Group B', id: 'GB', expanded: true, children: [
      {name: 'Resource 5', id: 'R5', capacity: 20},
      {name: 'Resource 6', id: 'R6', capacity: 40},
      {name: 'Resource 7', id: 'R7', capacity: 20},
      {name: 'Resource 8', id: 'R8', capacity: 40}
    ]
  }
];

This row will display the total number of events for each time slot:

onBeforeCellRender: args => {
  if (args.cell.resource === "summary") {
    const total = args.control.events.forRange(args.cell.start, args.cell.end);
    if (total.length > 0) {
      args.cell.properties.text = `${total.length}`;
    } else {
      args.cell.properties.text = "";
    }
    args.cell.properties.verticalAlignment = "center";
    args.cell.properties.horizontalAlignment = "center";
    args.cell.properties.backColor = "#d5e2fa";
  }
},

To highlight the frozen row and make clear that it has a special purpose, we set a custom background color for the grid cells:

onBeforeCellRender: args => {
  if (args.cell.resource === "summary") {

    // ...

    args.cell.properties.backColor = "#d5e2fa";
  }
},

And also for the row header:

onBeforeRowHeaderRender: args => {
  if (args.row.id === "summary") {
    args.row.backColor = "#cadffb";
  }
},

Full Source Code

Here is the full source of our Angular application that exports the Scheduler view to an Excel file (XLSX):

import {Component, ViewChild, AfterViewInit} from '@angular/core';
import {DayPilot, DayPilotModule, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import {DataService, ExtendedEventData} from './data.service';
import ExcelJS from 'exceljs';
import {FormsModule} from '@angular/forms';

@Component({
  selector: 'scheduler-component',
  standalone: true,
  imports: [DayPilotModule, FormsModule],
  providers: [DataService],
  template: `
    <div class="toolbar">
      <input type="text" placeholder="Filename" [(ngModel)]="filename" />
      <button (click)="exportToExcel()">Export</button>
    </div>
    <daypilot-scheduler [config]="config" [events]="events" #scheduler></daypilot-scheduler>
  `,
  styles: [`
    .toolbar {
      display: flex;
      align-items: center;
      padding: 8px;
      margin-bottom: 15px;
      background-color: #f8f9fa;
      border: 1px solid #ddd;
      border-radius: 4px;
    }

    .toolbar input[type="text"] {
      margin-right: 8px;
      padding: 6px 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-size: 14px;
      width: 200px;
    }

    .toolbar button {
      padding: 6px 12px;
      background-color: #6c757d;
      color: #ffffff;
      border: none;
      border-radius: 4px;
      font-size: 14px;
      cursor: pointer;
      transition: background-color 0.3s ease;
    }

    .toolbar button:hover {
      background-color: #5a6268;
    }
  `]
})
export class SchedulerComponent implements AfterViewInit {

  filename: string = "scheduler.xlsx";

  @ViewChild('scheduler')
  scheduler!: DayPilotSchedulerComponent;

  events: DayPilot.EventData[] = [];

  config: DayPilot.SchedulerConfig = {
    timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}],
    scale: "Day",
    days: 365,
    startDate: "2025-01-01",
    durationBarVisible: false,
    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
      });
    },
    treeEnabled: true,
    exceljs: ExcelJS,
    onBeforeRowHeaderRender: args => {
      if (args.row.id === "summary") {
        args.row.backColor = "#cadffb";
      }
    },
    onBeforeCellRender: args => {
      if (args.cell.resource === "summary") {
        const total = args.control.events.forRange(args.cell.start, args.cell.end);
        if (total.length > 0) {
          args.cell.properties.text = `${total.length}`;
        } else {
          args.cell.properties.text = "";
        }
        args.cell.properties.verticalAlignment = "center";
        args.cell.properties.horizontalAlignment = "center";
        args.cell.properties.backColor = "#d5e2fa";
      }
    },
    onBeforeEventRender: args => {
      const data = <ExtendedEventData>args.data;
      args.data.backColor = data.color;
      args.data.borderColor = data.color;
      args.data.fontColor = "#ffffff";
    }
  };

  constructor(private ds: DataService) {
  }

  ngAfterViewInit(): void {
    this.ds.getResources().subscribe(result => this.config.resources = result);

    this.scheduler.control.scrollTo("2025-10-01");

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

  exportToExcel(): void {
    const options = {
      area: "full"
    };
    this.scheduler.control.exportAs("xlsx", options).download(this.filename || "scheduler.xlsx");
  }

}

You can download the full project using the link at the top of this tutorial.