Features

  • How to display custom JSX in React Scheduler events

  • Compare the JSX syntax and features with built-in active areas (another options for adding rich content)

  • Both approaches (JSX and active areas) can be used side-by-side

  • 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.

Adding a React JSX Component to Scheduler Events

javascript scheduler rendering jsx in events onbeforeeventdomadd

Let’s start with a simple React Scheduler configuration that displays a couple of rows and events. You can use the code below or you can generate a new React project using the DayPilot UI Builder application.

import React, {Component} from 'react';
import {DayPilot, DayPilotScheduler} from "daypilot-pro-react";

class Scheduler extends Component {

  constructor(props) {
    super(props);

    this.state = {
      timeHeaders: [{"groupBy": "Month"}, {"groupBy": "Day", "format": "d"}],
      scale: "Day",
      days: 92,
      startDate: "2021-10-01",
      treeEnabled: true,
    };
  }

  componentDidMount() {

    // load resource and event data
    this.setState({
      resources: [
        {name: "Resource A", id: "A"},
        {name: "Resource B", id: "B"},
        // ...
      ],
      events: [
        {
          id: 1,
          text: "Event 1",
          start: "2021-11-02T00:00:00",
          end: "2021-11-05T00:00:00",
          resource: "A"
        },
        // ...
      ]
    });

  }

  render() {
    var {...config} = this.state;
    return (
      <div>
        <DayPilotScheduler {...config} />
      </div>
    );
  }
}

export default Scheduler;

Normally, you will specify the event content is using the text or html property of the event data object:

events: [
  {
    id: 1,
    text: "Event 1",
    start: "2021-11-02T00:00:00",
    end: "2021-11-05T00:00:00",
    resource: "A"
  },
  // ...
]

In React, you can use JSX to specify the event content. You can add a JSX element using args.element property in onBeforeEventDomAdd event handler:

import React, {Component} from 'react';
import {DayPilot, DayPilotScheduler} from "daypilot-pro-react";

class Scheduler extends Component {

  constructor(props) {
    super(props);

    this.state = {
      // ...
      onBeforeEventDomAdd: args => {
        args.element = <div>
          {args.e.data.text}
          <div style={{position: "absolute", right: "5px", top: "9px", width: "17px", height: "17px"}}
               onClick={() => this.deleteEvent(args.e)}><img src={"delete-17.svg"} alt={"Delete icon"}/></div>
        </div>;
      },
    };
  }

  deleteEvent(e) {
    this.scheduler.events.remove(e);
  };

  render() {
    var {...config} = this.state;
    return (
      <div>
        <DayPilotScheduler
          {...config}
        />
      </div>
    );
  }
}

export default Scheduler;

The example displays the default events text (args.e.data.text) and adds a delete-17.svg image at the right side of the event. The onClick event handler deletes the event from the Scheduler.

The Scheduler unmounts the JSX content when the event is removed from DOM.

Using Active Areas to Add Rich Content

javascript scheduler rendering jsx in events active areas

The Scheduler offers another way to add rich content to the Scheduler events, active areas. This is a programmatic way to add absolutely-positioned <div> elements at the specified location. The active areas can serve as simple styling tools but they will also let you add custom behavior.

In addition to custom event handler (onClick) the active areas can also trigger event moving, event resizing, or display a context menu or a bubble with event details.

Active area advantages over JSX:

This example adds an icon with the same functionality as the JSX element in the previous example:

import React, {Component} from 'react';
import {DayPilot, DayPilotScheduler} from "daypilot-pro-react";

class Scheduler extends Component {

  constructor(props) {
    super(props);

    this.state = {
      // ...
      onBeforeEventRender: args => {
        args.data.areas = [
          {right: 25, top: 10, width: 17, height: 17, image: "delete-17.svg", onClick: args => this.deleteEvent(args.source)}
        ];
      },
      onBeforeEventDomAdd: args => {
        args.element = <div>
          {args.e.data.text}
          <div style={{position: "absolute", right: "5px", top: "9px", width: "17px", height: "17px"}}
               onClick={() => this.deleteEvent(args.e)}><img src={"delete-17.svg"} alt={"Delete icon"}/></div>
        </div>;
      },
    };
  }

  deleteEvent(e) {
    this.scheduler.events.remove(e);
  };

  render() {
    var {...config} = this.state;
    return (
      <div>
        <DayPilotScheduler
          {...config}
        />
      </div>
    );
  }
}

export default Scheduler;

Full Source Code

Below is a full source code of the example. It displays the delete icon using both methods (JSX element and active areas) so you can compare the syntax.

Scheduler.js

import React, {Component} from 'react';
import {DayPilot, DayPilotScheduler} from "daypilot-pro-react";

class Scheduler extends Component {

  constructor(props) {
    super(props);

    this.state = {
      timeHeaders: [{"groupBy": "Month"}, {"groupBy": "Day", "format": "d"}],
      scale: "Day",
      days: 92,
      startDate: "2021-10-01",
      timeRangeSelectedHandling: "Enabled",
      onTimeRangeSelected: args => {
        var dp = this;
        DayPilot.Modal.prompt("Create a new event:", "Event 1").then(function (modal) {
          dp.clearSelection();
          if (modal.canceled) {
            return;
          }
          dp.events.add({
            start: args.start,
            end: args.end,
            id: DayPilot.guid(),
            resource: args.resource,
            text: modal.result
          });
        });
      },
      onBeforeEventRender: args => {
        args.data.areas = [
          {right: 25, top: 10, width: 17, height: 17, image: "delete-17.svg", onClick: args => this.deleteEvent(args.source)}
        ];
      },
      onBeforeEventDomAdd: args => {
        args.element = <div>
          {args.e.data.text}
          <div style={{position: "absolute", right: "5px", top: "9px", width: "17px", height: "17px"}}
               onClick={() => this.deleteEvent(args.e)}><img src={"delete-17.svg"} alt={"Delete icon"}/></div>
        </div>;
      },
      treeEnabled: true,
    };
  }

  deleteEvent(e) {
    this.scheduler.events.remove(e);
  };

  componentDidMount() {

    this.scheduler.scrollTo("2021-11-01");

    // load resource and event data
    this.setState({
      resources: [
        {name: "Resource A", id: "A"},
        {name: "Resource B", id: "B"},
        {name: "Resource C", id: "C"},
        {name: "Resource D", id: "D"},
        {name: "Resource E", id: "E"},
        {name: "Resource F", id: "F"},
        {name: "Resource G", id: "G"}
      ],
      events: [
        {
          id: 1,
          text: "Event 1",
          start: "2021-11-02T00:00:00",
          end: "2021-11-05T00:00:00",
          resource: "A"
        },
        {
          id: 2,
          text: "Event 2",
          start: "2021-11-03T00:00:00",
          end: "2021-11-10T00:00:00",
          resource: "C",
          barColor: "#38761d",
          barBackColor: "#93c47d"
        },
        {
          id: 3,
          text: "Event 3",
          start: "2021-11-02T00:00:00",
          end: "2021-11-08T00:00:00",
          resource: "D",
          barColor: "#f1c232",
          barBackColor: "#f1c232"
        },
        {
          id: 4,
          text: "Event 3",
          start: "2021-11-02T00:00:00",
          end: "2021-11-08T00:00:00",
          resource: "E",
          barColor: "#cc0000",
          barBackColor: "#ea9999"
        }
      ]
    });

  }

  render() {
    var {...config} = this.state;
    return (
      <div>
        <DayPilotScheduler
          {...config}
          ref={component => {
            this.scheduler = component && component.control;
          }}
        />
      </div>
    );
  }
}

export default Scheduler;