Features

  • Angular 2 project (using Angular CLI 1.0.0-beta.25.5)
  • Scheduler component that displays events for multiple resources
  • No backend required (resources and events are defined inline)
  • Shows how to split events into two or more phases with defined start/end and custom styles
  • Includes trial version of DayPilot Pro for JavaScript

See also a basic tutorial that explains how to start using DayPilot Scheduler in Angular 2 applications:

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.

Live Demo

You can test this project in a live demo:

Angular 2 Scheduler with Sample Event

angular2-scheduler-event-phases-default.png

We have a simple event that we want to display:

events: any[] = [
  {
    id: "1",
    resource: "R1",
    start: "2017-01-03",
    end: "2017-01-15",
    text: "Event 1"
  }
]

We will display the event using Angular 2 Scheduler from DayPilot Pro package. This is our Scheduler component that builds the UI using <daypilot-scheduler>:

import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot} 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")
  scheduler: DayPilot.Angular.Scheduler;

  events: any[] = [];

  config: any = {
    timeHeaders : [
      {groupBy: "Month", format: "MMMM yyyy"},
      {groupBy: "Day", format: "d"}
    ],
    scale: "Day",
    days: 31,
    startDate: "2017-01-01"
  };

  constructor(private ds: DataService, private cdr: ChangeDetectorRef) {}

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

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

      // this is required for getEvents() that resolves immediately (no http)
      this.cdr.detectChanges();
    });
  }

}

Event Phases

We want to split the event into three phases:

  • Preparation
  • Main Phase
  • Evaluation

Let's add the phase data to the event object (together with phase start and end dates):

events: any[] = [
  {
    id: "1",
    resource: "R1",
    start: "2017-01-03",
    end: "2017-01-15",
    text: "Event 1",
    phases: [
      { start: "2017-01-03", end: "2017-01-06", text: "Preparation" },
      { start: "2017-01-06", end: "2017-01-12", text: "Main Phase" },
      { start: "2017-01-12", end: "2017-01-15", text: "Evaluation" }
    ]
  }
]

We will use onBeforeEventRender event handler to customize the event. In the event handler, we will read the phase data from the event object and insert custom active areas at the specified dates.

angular2-scheduler-event-phases-areas.png

The event handler is specified using onBeforeEventRender method that we add to the "config" object.

import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot} 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")
  scheduler: DayPilot.Angular.Scheduler;

  events: any[] = [];

  config: any = {
  
    // ...
  
    onBeforeEventRender: args => {
      if (args.data.phases) {

        // hide the default event content and tooltip
        args.data.barHidden = true;
        args.data.html = '';
        args.data.toolTip = '';

        if (!args.data.areas) {
          args.data.areas = [];
        }
        args.data.phases.forEach(phase => {
          args.data.areas.push({
            start: phase.start,
            end: phase.end,
            top: 0,
            bottom: 0,
            html: phase.text
          });
        });
      }
    }

  };
  
  // ...

}

The active area positions are specified using a combination of start/end/top/bottom properties. Start and end accept a DayPilot.Date object (or an ISO 8601 datetime string that will be converted to DayPilot.Date automatically). Top and bottom specify the distance from event edges in pixels.

Customizing the Phases Appearance

angular2-scheduler-event-phases-styling.png

By default the active areas that display the event phases don't use any styling. We will add a few more properties to the event object (toolTip, background):

events: any[] = [
  {
    id: "1",
    resource: "R1",
    start: "2017-01-03",
    end: "2017-01-15",
    text: "Event 1",
    phases: [
      { start: "2017-01-03", end: "2017-01-06", text: "Preparation", toolTip: "Preparation", background: "#b6d7a8"},
      { start: "2017-01-06", end: "2017-01-12", text: "Main Phase", toolTip: "Main Phase", background: "#93c47d"},
      { start: "2017-01-12", end: "2017-01-15", text: "Evaluation", toolTip: "Evaluation", background: "#6aa84f"}
    ]
  }
]

The modified version of onBeforeEventRender event handler uses these properties to apply custom styles and

import {Component, ViewChild, AfterViewInit, ChangeDetectorRef} from "@angular/core";
import {DayPilot} 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")
  scheduler: DayPilot.Angular.Scheduler;

  events: any[] = [];

  config: any = {

    // ...
  
    onBeforeEventRender: args => {
      if (args.data.phases) {

        // hide the default event content and tooltip
        args.data.barHidden = true;
        args.data.html = '';
        args.data.toolTip = '';

        if (!args.data.areas) {
          args.data.areas = [];
        }
        args.data.phases.forEach(phase => {
          args.data.areas.push({
            start: phase.start,
            end: phase.end,
            top: 0,
            bottom: 0,
            css: phase.css,
            style: "overflow:hidden; padding: 3px; box-sizing: border-box;",
            background: phase.background,
            html: phase.text,
            toolTip: phase.toolTip
            });
        });
      }
    }
  };

  // ...

}

Updating Phases during Drag and Drop Moving

In order to display the phases correctly after the event is moved using drag and drop, we will add onMoveEvent handler that updates the start/end date of each phase according to the new location.

config: any = {
  // ...
  onEventMove: args => {
    let offset = new DayPilot.Duration(args.e.start(), args.newStart);
    args.e.data.phases.forEach(phase =>{
      phase.start = new DayPilot.Date(phase.start).addTime(offset);
      phase.end = new DayPilot.Date(phase.end).addTime(offset);
    });
  }
  // ..
};

You can use the same approach for event resizing. The event resizing handler isn't implemented - the exact behavior will be different depending on the application logic.