Overview

The upper-left corner of the Angular Scheduler component is empty by default. You can add custom content using the cornerHtml property. However, this property only supports raw HTML and it won’t let you use an Angular template or elements with custom events.

In order to display dynamic content, it’s necessary to create a custom Angular component and add a new instance dynamically to the Scheduler corner using onBeforeCornerDomAdd event handler.

The sample 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. Buy a license.

Button: Custom Angular Component

First, let’s create a simple Button Angular component.

import {Component, ViewChild, AfterViewInit, Input} from '@angular/core';
import {DayPilot} from "daypilot-pro-angular";

@Component({
  selector: 'scheduler-component',
  template: `<button (click)="click()">{{text}}</button>`,
  styles: [`
  button {
    background-color: #3c78d8;
    border: 1px solid #1155cc;
    color: #fff;
  }
  `]

})
export class ButtonComponent {

  @Input()
  text: string = "button";

  click() {
    DayPilot.Modal.alert("Button clicked");
  }
}

How to Add the Button to the Upper-Left Corner of the Angular Scheduler?

Now we will use the onBeforeCornerDomAdd Scheduler event to add our Button component to the upper-left corner.

First, we need to create an instance of the component. Angular 13 provides a simplified API for dynamic component creation and the only thing we need is an instance of ViewContainerRef:

const component: ComponentRef<ButtonComponent> = this.viewContainerRef.createComponent(ButtonComponent);

As soon as we have created the component instance we can set its properties (if needed). Our Button component has a text property and we will use it to set the button text. After changing the component properties, it is necessary to invoke change detection.

component.instance.text = this.scheduler.control.startDate?.toString("yyyy") || "";
component.changeDetectorRef.detectChanges();

Now we can get a reference to the native DOM element and display it in the Scheduler corner using args.element:

args.element = component.location.nativeElement;

This is how our onBeforeCornerDomAdd event looks now:

import {Component, ViewChild, AfterViewInit, ViewContainerRef, ComponentRef} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import {DataService} from './data.service';
import {ButtonComponent} from "./button.component";

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

  // ...

  config: DayPilot.SchedulerConfig = {
    onBeforeCornerDomAdd: args => {
      const component: ComponentRef<ButtonComponent> = this.viewContainerRef.createComponent(ButtonComponent);

      component.instance.text = this.scheduler.control.startDate?.toString("yyyy") || "";
      component.changeDetectorRef.detectChanges();

      args.element = component.location.nativeElement;
      (<any>args).component = component;
    },
    // ...
  };

  constructor(private ds: DataService,
              private viewContainerRef: ViewContainerRef) {
  }

}

Cleanup: Destroy the Component

When the Angular Scheduler corner content is updated or when the Scheduler component is destroyed, the old content is removed. At this point, it is necessary to destroy the dynamic Button component as well.

As you may have noticed, we saved the component object in the args object in onBeforeCornerDomAdd event. The same args object will be available in onBeforeCornerDomRemove event which we will use to destroy the component.

(<any>args).component = component;

The args object doesn’t have any component property so it was necessary to cast the args object to any.

In onBeforeCornerDomRemove, we will load the component and call the destroy() method:

onBeforeCornerDomRemove: args => {
  const component = (<any>args).component;
  component.destroy();
},