Notes

  • Resources are displayed on the vertical (Y) axis.

  • In Gantt and Timesheet (Days) modes the rows will be generated automatically. The Resources array will have no effect.

  • Each resource has an ID that is used for arranging events into the rows (it must match event.resource property).

  • Resources can be organized in a tree hierarchy.

JavaScript Scheduler

How to Initialize the Scheduler Rows

You can specify the resources using resources property during Scheduler initialization:

<div id="dp"></div>
<script type="text/javascript">

  var dp = new DayPilot.Scheduler("dp");
  // ...
  dp.resources = [
    { name: "Room A", id: "A" },
    { name: "Room B", id: "B" },
    { name: "Room C", id: "C" }
  ];
  dp.init();
</script>

How to Update the Scheduler Rows

You can also update the resources later by updating the resources array and calling update():

dp.resources = [
  { name: "Room A", id: "A" },
  { name: "Room B", id: "B" },
  { name: "Room C", id: "C" },
  { name: "Room D", id: "D" }
];
dp.update();

The update() method accepts a config object as a parameter. That lets you specify the properties to be updated:

const = resources = [
  { name: "Room A", id: "A" },
  { name: "Room B", id: "B" },
  { name: "Room C", id: "C" },
  { name: "Room D", id: "D" }
];
dp.update({resources});

How to Load Row Data using a REST API Call

You can also use a helper method that loads the resources using an HTTP call and updates the Scheduler:

dp.rows.load("/api/resources");

The specified URL must return the resources in JSON format:

[
  { "name": "Room A", "id": "A" },
  { "name": "Room B", "id": "B" },
  { "name": "Room C", "id": "C" },
  { "name": "Room D", "id": "D" }
]

JavaScript Tutorials

Angular Scheduler

You can update the resources of the Angular Scheduler component using the following methods:

  1. Automatic change detection (config attribute)

  2. Direct API

The automatic change detection of the object specified using config attribute is convenient but the performance degrades if you use it with a large config object. If you display many resource in the Angular Scheduler, the config object can grow very quickly. See also Angular Scheduler Performance topic.

1. Automatic change detection. You can load resource by modifying the resources property of the config object:

import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import {DataService} from './data.service';

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

  @ViewChild('scheduler')
  scheduler!: DayPilotSchedulerComponent;

  events: DayPilot.EventData[] = [];

  config: DayPilot.SchedulerConfig = {
    days: DayPilot.Date.today().daysInMonth(),
    startDate: DayPilot.Date.today().firstDayOfMonth(),

  };

  constructor(private ds: DataService) {
  }

  ngAfterViewInit(): void {
    this.ds.getResources().subscribe((result: DayPilot.ResourceData[]) => this.config.resources = result);
  }

}

2. Use the direct API. This way the resources will be loaded directly to the Angular Scheduler and bypass the change detection.

import {AfterViewInit, Component, ViewChild} from '@angular/core';
import {DayPilot, DayPilotSchedulerComponent} from 'daypilot-pro-angular';
import {DataService} from './data.service';

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

  @ViewChild('scheduler')
  scheduler!: DayPilotSchedulerComponent;

  events: DayPilot.EventData[] = [];

  config: DayPilot.SchedulerConfig = {
    days: DayPilot.Date.today().daysInMonth(),
    startDate: DayPilot.Date.today().firstDayOfMonth(),

  };

  constructor(private ds: DataService) {
  }

  ngAfterViewInit(): void {
    
    this.ds.getResources().subscribe((resources: DayPilot.ResourceData[]) => this.scheduler.control.update({resources}));
  }

}

Angular Tutorials

React Scheduler

There are two ways to load resource in the React Scheduler component. In React, both methods (automatic state detection and direct API call) have the same performance.

1. Use the resources attribute of <DayPilotScheduler> tag. In this example, the React Scheduler loads all properties from the this.state object as attributes. In order to load resources, simply update the resources property of the this.state object.

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: DayPilot.Date.today().daysInMonth(),
      startDate: DayPilot.Date.today().firstDayOfMonth(),
      treeEnabled: true, 
      // ...
    };
  }

  componentDidMount() {

    const resources = [
      {name: "Group A", id: "GroupA", expanded: true, children: [
          {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"}
        ]
      },
      {name: "Group B", id: "GroupB", expanded: true, children: [
          {name: "Resource H", id: "H"},
          {name: "Resource I", id: "I"},
        ]}
    ];
    
    this.setState({resources});

  }

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

export default Scheduler;

2. Use the direct API. You can update the resources by calling the update() method. All properties of the object passed as the parameter will be applied to the React Scheduler component.

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: DayPilot.Date.today().daysInMonth(),
      startDate: DayPilot.Date.today().firstDayOfMonth(),
      treeEnabled: true, 
      // ...
    };
  }

  componentDidMount() {

    const resources = [
      {name: "Group A", id: "GroupA", expanded: true, children: [
          {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"}
        ]
      },
      {name: "Group B", id: "GroupB", expanded: true, children: [
          {name: "Resource H", id: "H"},
          {name: "Resource I", id: "I"},
        ]}
    ];
    
    this.scheduler.update({resources});

  }

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

export default Scheduler;

React Tutorials

ASP.NET WebForms

Static configuration (.aspx)

<DayPilot:DayPilotScheduler 
  ID="DayPilotScheduler1" 
  runat="server" 
  TreeEnabled="true"
  ...
  >
  <Resources>
      <DayPilot:Resource Name="Locations" Value="GroupLocations" Expanded="True">
          <Children>
              <DayPilot:Resource Name="Room 1" Value="A" Expanded="False" />
              <DayPilot:Resource Name="Room 2" Value="B" Expanded="False" />
              <DayPilot:Resource Name="Room 3" Value="C" Expanded="False" />
              <DayPilot:Resource Name="Room 4" Value="D" Expanded="False" />
          </Children>
      </DayPilot:Resource>
      <DayPilot:Resource Name="People" Value="GroupPeople" Expanded="True">
          <Children>
          <DayPilot:Resource Name="Person 1" Value="E" Expanded="False" />
          <DayPilot:Resource Name="Person 2" Value="F" ToolTip="Test" Expanded="False" />
          <DayPilot:Resource Name="Person 3" Value="G" ToolTip="Test" Expanded="False" />
          <DayPilot:Resource Name="Person 4" Value="H" ToolTip="Test" Expanded="False" />
          </Children>
      </DayPilot:Resource>
      <DayPilot:Resource Name="Tools" Value="GroupTools" Expanded="True">
          <Children>
          <DayPilot:Resource Name="Tool 1" Value="I" Expanded="False" />
          <DayPilot:Resource Name="Tool 2" Value="J" ToolTip="Test" Expanded="False" />
          <DayPilot:Resource Name="Tool 3" Value="K" ToolTip="Test" Expanded="False" />
          <DayPilot:Resource Name="Tool 4" Value="L" ToolTip="Test" Expanded="False" />
          </Children>
      </DayPilot:Resource>
 </Resources>
</DayPilot:DayPilotScheduler>

Loading Resources from a Database

Resources only need to be set once (in Page_Load). 

protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack)
  {
    LoadResources();
  }
}

private void LoadResources()
{
  DataTable locations = new DataManager().GetLocations();
  DayPilotScheduler1.Resources.Clear();
  foreach (DataRow location in locations.Rows)
  {
    int id = Convert.ToInt32(location["LocationId"]);

    Resource r = new Resource((string)location["LocationName"], null); // using null for resources that can't be used
    r.IsParent = true; // marking as parent for the case that no children are loaded
    r.Expanded = true;
    DayPilotScheduler1.Resources.Add(r);

    DataTable rooms = new DataManager().GetLocations(id, Filter.Seats);
    
    foreach (DataRow dr in rooms.Rows)
    {
      Resource c = new Resource((string)dr["LocationName"], Convert.ToString(dr["LocationId"]));
      r.Children.Add(c);
    }
  }
}

The resources collection is persisted during subsequent PostBacks and CallBacks. This increases the size of the request/response but it is convenient and it keeps. 

This behavior can be turned off using SyncResourceTree property (SyncResourceTree="false"). In this case it is necessary to load the resources during every request:

protected void Page_Load(object sender, EventArgs e)
{
  if (!IsPostBack)
  {
    // ...
  }

  LoadResources();
}

See also How to load the Scheduler resource tree from a database (SQL Server) (KB).

ASP.NET MVC

Resources only need to be set once (in OnInit). It is persisted during subsequent PostBacks and CallBacks.

protected override void OnInit(InitArgs e)
{
  LoadResources();

  UpdateWithMessage("Welcome!", CallBackUpdateType.Full);
}

private void LoadResources()
{
  foreach (DataRow r in new EventManager().GetResources().Rows)
  {
      Resources.Add((string) r["name"], Convert.ToString(r["id"]));
  }
}

Note that changing the resources requires full update:

UpdateWithMessage("Welcome!", CallBackUpdateType.Full);

The Scheduler resources (rows) can be created directly in the view or in the controller.

Creating Resources in the MVC View

@Html.DayPilotScheduler("dps", new DayPilotSchedulerConfig {
  BackendUrl = ResolveUrl("~/Scheduler/Backend"),
  Resources = new ResourceCollection {
      new Resource{Name = "Room A", Id = "A", Expanded = true, Children = new ResourceCollection
        {
            new Resource("Room A.1", "A.1"),
            new Resource("Room A.2", "A.2"),
            new Resource("Room A.3", "A.3")
        }},
      new Resource("Room B", "B"),
      new Resource("Room C", "C"),
      new Resource("Room D", "D")
  }
})

Creating Resources in the Backend Controller

The Resources collection should be filled in the OnInit() event handler. This event will be called immediately after the Scheduler is initialized on the client side. It is called only once.

The Resources collection will be persisted during all subsequent callback calls and it is not necessary to rebuild it on every callback.

public class SchedulerController : Controller
{
  //
  // GET: /Scheduler/

  public ActionResult Backend()
  {
      return new Dps().CallBack(this);
  }

  class Dps : DayPilotScheduler
  {
    protected override void OnInit(InitArgs e)
    {
      Resources.Add("Room A", "A");
      Resources.Add("Room B", "B");
      Resources.Add("Room C", "C");
      Resources.Add("Room D", "D");
      Resources.Add("Room E", "E");

      UpdateWithMessage("Welcome!", CallBackUpdateType.Full);
    }

    protected override void OnFinish()
    {
      if (UpdateType == CallBackUpdateType.None)
      {
          return;
      }

      Events = new EventManager().FilteredData(StartDate, StartDate.AddDays(Days)).AsEnumerable();

      DataIdField = "id";
      DataTextField = "name";
      DataStartField = "eventstart";
      DataEndField = "eventend";
      DataResourceField = "resource";
    }
  }
}