Overview

  • Define custom JavaScript Scheduler event types

  • Customize the appearance depending on event type

  • Change event type using a context menu

  • Change event type using a modal dialog

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

Storing Event Type

The best place to store the event type (we are going to use type property) is the tags property of the event data object. Storing custom data under tags avoids future conflicts with the reserved property names at the top level.

dp.events.list = [
  {
    id: 1,
    text: "Event 1",
    start: "2022-03-05T00:00:00",
    end: "2022-03-09T00:00:00",
    resource: "R2",
    tags: {
      type: "standard"
    }
  },
  {
    id: 2,
    text: "Event 2",
    start: "2022-03-07T00:00:00",
    end: "2022-03-15T00:00:00",
    resource: "R4",
    tags: {
      type: "important"
    }
  },
];

Appearance

javascript-scheduler-event-types-appearance.png

Now we need to define the appearance for the different event types. This can be done using onBeforeEventRender event handler. In this example, we use a custom duration bar color (barColor property) but you can add your own text/HTML, icons, CSS classes and so on.

onBeforeEventRender: args => {
  const type = args.data.tags && args.data.tags.type;
  switch (type) {
    case "standard":
      args.data.barColor = "#38761d";
      args.data.barBackColor = "#38761d";
      break;
    case "important":
      args.data.barColor = "#cc0000";
      args.data.barBackColor = "#cc0000";
      break;
  }
},

Changing Event Type using Context Menu

javascript-scheduler-event-types-context-menu.png

In this step, we will add an option to change the Scheduler event type using context menu. The context menu will display all event types and the current one will be highlighted using a checkmark icon.

Normally, the context menu items are pre-defined using the items property. But we need to generate the items from the list of event types and highlight the current type. We will use onShow event to modify the context menu items right before the menu is displayed:

contextMenu: new DayPilot.Menu({
  items: [],
  onShow: args => {
    const e = args.source;

    // generate menu items dynamically
    dp.contextMenu.items = [
      {text: "Edit...", onClick: async args =>  edit(args.source) },
      {text: "-"}
    ];
    types.forEach(type => {
      const item = {
        text: type.name,
        onClick: args => changeType(args.source, type.id)
      };
      if (type.id === e.data.tags.type) {
        item.image = "svg/checkmark-17.svg";
      }
      dp.contextMenu.items.push(item);
    });
  }
}),

The changeType() function changes the event data object and calls events.update() to apply the changes:

function changeType(e, type) {
  e.data.tags.type = type;
  dp.events.update(e);
}

Changing Event Type using Modal Dialog

javascript-scheduler-event-types-modal-dialog.png

First, we will configure the Scheduler to display a modal dialog with event details on click:

onEventClick: async args => edit(args.e),

The edit() function opens a modal dialog using DayPilot.Modal.form(). You can design a custom modal dialog using DayPilot Modal Builder.

The modal form fields are mapped directly to the event data object (text ang tags.type properties).

const types = [
  {name: "Standard", id: "standard"},
  {name: "Important", id: "important"},
];

const form = [
  {name: "Event name", id: "text"},
  {name: "Event type", id: "tags.type", type: "select", options: types}
];


async function edit(e) {
  const modal = await DayPilot.Modal.form(form, e.data);
  if (modal.canceled) {
    return;
  }
  dp.events.update(modal.result);
}

Full Source Code

And here is the full source code of the JavaScript Scheduler component displaying custom event types:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScript Scheduler: Event Types</title>

  <!-- DayPilot library -->
  <script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
  <h1><a href='https://code.daypilot.org/96153/javascript-scheduler-event-types'>JavaScript Scheduler: Event Types</a></h1>
  <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React/Vue</div>
</div>

<div class="main">
  <div id="dp"></div>
  <div class="generated">Generated using <a href="https://builder.daypilot.org/">DayPilot UI Builder</a>.</div>
</div>

<script>

  const types = [
    {name: "Standard", id: "standard"},
    {name: "Important", id: "important"},
  ];

  const form = [
    {name: "Event name", id: "text"},
    {name: "Event type", id: "tags.type", type: "select", options: types}
  ];

  const dp = new DayPilot.Scheduler("dp", {
    timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}],
    scale: "Day",
    days: 31,
    startDate: "2022-03-01",
    timeRangeSelectedHandling: "Enabled",
    onTimeRangeSelected: async args => {
      const data = {
        text: "Event 1",
        start: args.start,
        end: args.end,
        resource: args.resource,
        id: DayPilot.guid(),
        tags: {
          type: "standard"
        }
      };
      const modal = await DayPilot.Modal.form(form, data);
      dp.clearSelection();
      if (modal.canceled) { return; }
      console.log("modal.result", modal.result);
      dp.events.add(modal.result);
    },
    onBeforeEventRender: args => {
      const type = args.data.tags && args.data.tags.type;
      switch (type) {
        case "standard":
          args.data.barColor = "#38761d";
          args.data.barBackColor = "#38761d";
          break;
        case "important":
          args.data.barColor = "#cc0000";
          args.data.barBackColor = "#cc0000";
          break;
      }

      args.data.areas = [
        {
          right: 5,
          top: 10,
          height: 16,
          width: 16,
          symbol: "svg/daypilot.svg#minichevron-down-2",
          action: "ContextMenu",
          fontColor: "#ccc",
          style: "border: 1px solid #ccc"
        }
      ]
    },
    contextMenu: new DayPilot.Menu({
      items: [],
      onShow: args => {
        const e = args.source;

        // generate menu items dynamically
        dp.contextMenu.items = [
          {text: "Edit...", onClick: async args =>  edit(args.source) },
          {text: "-"}
        ];
        types.forEach(type => {
          const item = {
            text: type.name,
            onClick: args => changeType(args.source, type.id)
          };
          if (type.id === e.data.tags.type) {
            item.image = "svg/checkmark-17.svg";
          }
          dp.contextMenu.items.push(item);
        });
      }
    }),
    treeEnabled: true,
  });
  dp.resources = [
    {name: "Resource 1", id: "R1"},
    {name: "Resource 2", id: "R2"},
    {name: "Resource 3", id: "R3"},
    {name: "Resource 4", id: "R4"},
    {name: "Resource 5", id: "R5"},
    {name: "Resource 6", id: "R6"},
    {name: "Resource 7", id: "R7"},
    {name: "Resource 8", id: "R8"},
    {name: "Resource 9", id: "R9"},
  ];
  dp.events.list = [
    {
      id: 1,
      text: "Event 1",
      start: "2022-03-05T00:00:00",
      end: "2022-03-09T00:00:00",
      resource: "R2",
      tags: {
        type: "standard"
      }
    },
    {
      id: 2,
      text: "Event 2",
      start: "2022-03-07T00:00:00",
      end: "2022-03-15T00:00:00",
      resource: "R4",
      tags: {
        type: "important"
      }
    },
  ];
  dp.init();


  async function edit(e) {
    const modal = await DayPilot.Modal.form(form, e.data);
    if (modal.canceled) {
      return;
    }
    dp.events.update(modal.result);
  }

  function changeType(e, type) {
    e.data.tags.type = type;
    dp.events.update(e);
  }

</script>

</body>
</html>