Overview

  • Add a context menu icon to the upper-left corner of the JavaScript Scheduler using an active area
  • Dynamically build the context menu items on show
  • Show check marks next to visible column names in the context menu
  • Requires DayPilot Pro for JavaScript 2020.2.4373 or later
  • 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.

Live Demo

Define Columns and Data

javascript-scheduler-show-hide-columns-define.png

Lets start with the following configuration that displays three custom columns in the row headers (Name, ID, Capacity):

var dp = new DayPilot.Scheduler("dp", {
  rowHeaderColumns: [
    {name: "Name", display: "name"},
    {name: "ID", display: "id"},
    {name: "Capacity", display: "capacity"},
  ],
  // ...
});
dp.resources = [
  {name: "Resource 1", id: "R1", capacity: 50},
  {name: "Resource 2", id: "R2", capacity: 10},
  {name: "Resource 3", id: "R3", capacity: 10},
  {name: "Resource 4", id: "R4", capacity: 50},
  {name: "Resource 5", id: "R5", capacity: 20},
  {name: "Resource 6", id: "R6", capacity: 30},
  {name: "Resource 7", id: "R7", capacity: 50},
  {name: "Resource 8", id: "R8", capacity: 60},
  {name: "Resource 9", id: "R9", capacity: 50},
];

Add Icon that Opens a Context Menu

javascript-scheduler-show-hide-columns-header-icon.png

We will add an icon to the upper-left corner using an active area defined in onBeforeCornerRender event handler.

var dp = new DayPilot.Scheduler("dp", {
  onBeforeCornerRender: function(args) {
    args.areas = [
      {
        right: 5,
        top: 5,
        height: 20,
        width: 20,
        action: "ContextMenu",
        icon: "icon icon-menu",
        cssClass: "area-open-menu",
        menu: new DayPilot.Menu()
      }
    ]
  }
});

Add Context Menu Item that Toggles "Capacity" Column

javascript-scheduler-show-hide-columns-toggle.png

In this step, we add a testing menu item that toggles visibility of the third column ("Capacity").

It changes the hidden property of the respective rowHeaderColumns item and requests a partial update() that only refreshes the row headers.

var dp = new DayPilot.Scheduler("dp", {
  onBeforeCornerRender: function(args) {
    args.areas = [
      {
        right: 5,
        top: 5,
        height: 20,
        width: 20,
        action: "ContextMenu",
        icon: "icon icon-menu",
        cssClass: "area-open-menu",
        menu: new DayPilot.Menu({
          items: [
            { text: "Toggle 'Capacity' column", 
              onClick: function(args) { 
                dp.rowHeaderColumns[2].hidden = !dp.rowHeaderColumns[2].hidden;
                dp.update({rowHeaderColumns: dp.rowHeaderColumns});
              }
            }
          ]
        })
      }
    ]
  }
});

Generate the Menu Items Dynamically

javascript-scheduler-show-hide-columns-dynamic-context-menu.png

In this final step, we use the onShow event handler to generate the context menu items dynamically from the columns array.

Each visible column will also show a check mark icon.

Clicking the menu item will toggle the column visibility.

If there is just one column visible, we will disable the corresponding menu item to make sure there is at least one column visible.

var dp = new DayPilot.Scheduler("dp", {
  onBeforeCornerRender: function(args) {
    args.areas = [
      {
        right: 5,
        top: 5,
        height: 20,
        width: 20,
        action: "ContextMenu",
        icon: "icon icon-menu",
        cssClass: "area-open-menu",
        menu: new DayPilot.Menu({
          onShow: function(args) {
            var menu = this;
            menu.items = [];
            dp.rowHeaderColumns.forEach(function(col) {
               menu.items.push({
                 _column: col,
                 text: col.name,
                 icon: col.hidden ? "" : "icon icon-checked",
                 onClick: function(args) {
                   // hide the menu, normally it stays visible until onClick completes
                   menu.hide();
                   var column = args.item._column;
                   column.hidden = !column.hidden;
                   // optimized update
                   dp.update({rowHeaderColumns: dp.rowHeaderColumns});
                 }
               });
            });
            var visible = menu.items.filter(function(item) { return !item._column.hidden; });
            // only one column visible, prevent action
            if (visible.length === 1) {
              visible[0].disabled = true;
            }
          }
        })
      }
    ]
  }
});

Full Source Code

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>JavaScript Scheduler: Show/Hide Columns using Context Menu</title>

  <style type="text/css">
    <!-- ... -->
  </style>

  <style>
    i.icon { font-style: normal; }
    .icon-checked:before {
      content: '\2714';
    }
    .icon-menu:before {
      content: '\2BC6';
    }
    .scheduler_default_main .area-open-menu {
      font-size: 14px;
      border: 1px solid #ccc;
      box-sizing: border-box;
      background-color: white;
      text-align: center;
      padding: 1px;
      cursor: pointer;
    }
  </style>

  <!-- DayPilot library -->
  <script src="js/daypilot/daypilot-all.min.js"></script>
</head>
<body>
<div class="header">
  <h1><a href='https://code.daypilot.org/49959/javascript-scheduler-show-hide-columns-using-context-menu'>JavaScript Scheduler: Show/Hide Columns using Context Menu</a></h1>
  <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React</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>
  var dp = new DayPilot.Scheduler("dp", {
    timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}],
    scale: "Day",
    days: DayPilot.Date.today().daysInMonth(),
    startDate: DayPilot.Date.today().firstDayOfMonth(),
    timeRangeSelectedHandling: "Enabled",
    onTimeRangeSelected: function (args) {
      var dp = this;
      DayPilot.Modal.prompt("Create a new event:", "Event 1").then(function(modal) {
        dp.clearSelection();
        if (!modal.result) { return; }
        dp.events.add(new DayPilot.Event({
          start: args.start,
          end: args.end,
          id: DayPilot.guid(),
          resource: args.resource,
          text: modal.result
        }));
      });
    },
    rowHeaderColumns: [
      {name: "Name", display: "name"},
      {name: "ID", display: "id"},
      {name: "Capacity", display: "capacity"},
    ],
    treeEnabled: true,
    rowHeaderHideIconEnabled: true,
    onBeforeCornerRender: function(args) {
      args.areas = [
        {
          right: 5,
          top: 5,
          height: 20,
          width: 20,
          action: "ContextMenu",
          icon: "icon icon-menu",
          cssClass: "area-open-menu",
          menu: new DayPilot.Menu({
            onShow: function(args) {
              var menu = this;
              menu.items = [];
              dp.rowHeaderColumns.forEach(function(col) {
                 menu.items.push({
                   _column: col,
                   text: col.name,
                   icon: col.hidden ? "" : "icon icon-checked",
                   onClick: function(args) {
                     // hide the menu, normally it stays visible until onClick completes
                     menu.hide();
                     var column = args.item._column;
                     column.hidden = !column.hidden;
                     // optimized update
                     dp.update({rowHeaderColumns: dp.rowHeaderColumns});
                   }
                 });
              });
              var visible = menu.items.filter(function(item) { return !item._column.hidden; });
              // only one column visible, prevent action
              if (visible.length === 1) {
                visible[0].disabled = true;
              }
            }
          })
        }
      ]
    }
  });
  dp.resources = [
    {name: "Resource 1", id: "R1", capacity: 50},
    {name: "Resource 2", id: "R2", capacity: 10},
    {name: "Resource 3", id: "R3", capacity: 10},
    {name: "Resource 4", id: "R4", capacity: 50},
    {name: "Resource 5", id: "R5", capacity: 20},
    {name: "Resource 6", id: "R6", capacity: 30},
    {name: "Resource 7", id: "R7", capacity: 50},
    {name: "Resource 8", id: "R8", capacity: 60},
    {name: "Resource 9", id: "R9", capacity: 50},
  ];
  dp.events.list = [];
  dp.init();
</script>

</body>
</html>