Loading data

Loading data

Which data should be retrieved from the database and how is decided by the developer.

The library just provides class DHTMLX.Scheduler.Data.SchedulerAjaxData which takes and renders a collection of data objects in JSON format supported by the scheduler (the collection must implement the IEnumerable interface).

 
Code samples included in the documentation (as well as the samples included in the package), use LINQ to SQL to access a database.
For each LINQ to SQL designer file added to the solution, Visual Studio automatically generates a LINQ to SQL DataContext class. The DataContext class used in the code samples is named as DHXSchedulerDataContext.

Tip! A sample DB structure you can see here.

Ajax loading

By default, data to the scheduler is loaded in the JSON format. And generally, to render a collection of objects you need to use the SchedulerAjaxData class.

  • In MVC you should apply the following technique:

    public ContentResult Data()
    {
        var events = (new DHXSchedulerDataContext()).Events;
        return (new SchedulerAjaxData(events));
    }
    • 'Events' is the name of mapping data table
    • SchedulerAjaxData is implicitly converted to type ContentResult
  • In case you use WebForms, apply another technique:

    public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "text/json";
        var events = (new DHXSchedulerDataContext()).Events;
        context.Response.Write(new SchedulerAjaxData(events).ToString());
    }
    • The response content type should be specified explicitly
    • SchedulerAjaxData is explicitly converted to string as well

Big datasets

By default, Scheduler loads all data at once. But it may become problematic when you are using big event collections. In such situations, you should use dynamic loading and load data by parts, necessary to fill the viewable area of Scheduler.

To enable dynamic loading you need to call method EnableDynamicLoading():

public ActionResult Index(){
  ...          
  scheduler.EnableDynamicLoading(SchedulerDataLoader.DynamicalLoadingMode.Day);
  ...
}

Enumeration SchedulerDataLoader.DynamicalLoadingMode has 3 possible values:

  • year;
  • month;
  • week;
  • day.

For example, if you set the 'month' mode, Scheduler will request data just for the current month and load remaining ones on demand.

Generated requests look like:

Data?from=DATEHERE&to=DATEHERE

where DATEHERE - a valid date value of the “yyyy-MM-dd” format.

The received data can be parsed as follows:

var dateFrom = DateTime.ParseExact(this.Request.QueryString["from"], "yyyy-MM-dd", CultureInfo.InvariantCulture);
var dateTo = DateTime.ParseExact(this.Request.QueryString["to"], "yyyy-MM-dd", CultureInfo.InvariantCulture);

Static loading

There are 2 ways to load data statically:

  1. Via method parse():

    public ActionResult Index() {
       var sched = new DHXScheduler(this);
       var context = new DHXSchedulerDataContext();           
       sched.Data.Parse(context.Events);
       sched.EnableDataprocessor = true;
       return View(sched);
    }

    Added items are stored in the inner object of the DHXSchedulerDataStore class - scheduler.Data.Pull.

    You can get a certain item by its index using:

    var item = scheduler.Data.Pull[0];
  2. Via helper DHTMLX:

    <%= HttpHelper.DHTMLX().Scheduler(Model.scheduler, Model.data); %>

Data to load

Data you can load is:

  • Model object

    var context = new DHXSchedulerDataContext();
    var data = new SchedulerAjaxData(context.Events);
    return data.Render();

    where 'Events' is the name of mapping data table

  • Data Collection

    var items = new List<object>(){
           new { id = "1", text = "first event", start_date = "03.06.2011", end_date = "04.06.2011" },
           new { id = "2", text = "second event", start_date = "05.06.2011", end_date = "06.06.2011" },
           new { id = "3", text = "third event", start_date = "07.06.2011", end_date = "08.06.2011" }
    };
     
    var data = new SchedulerAjaxData(items);
    return data.Render();

Data requirements

To be correctly processed, data for events must fit with some requirements.

Mandatory properties

Your data item must contain the following properties:

  • id - (int, string and etc.) the event id;
  • start_date (DateTime or string) - the date when a task is scheduled to begin. The default format - ”%m/%d/%Y %H:%i”;
  • end_date (DateTime or string) - the date when a task is scheduled to be completed. The default format - ”%m/%d/%Y %H:%i”;
  • text (string ) - the text of a task.

Format string

  • See available variations of the format string here.

Data format

  • In order to the data can be able to convert into JSON, date can't contain cross references.

Sample DB structure

A basic db for storing scheduler events can be created as in:

CREATE TABLE [Events](
  [id] int IDENTITY(1,1) NOT NULL,
  [text] nvarchar(256) NULL,
  [start_date] datetime NOT NULL,
  [end_date] datetime NOT NULL,
  PRIMARY KEY (id)
)

scheduler database structure

Custom names for data properties

Starting from version 3.0, you can use any names for the mandatory data properties.
To use a custom name for a mandatory data property, use the [DHXJson(Alias = 'mandatory_name')] serialization attribute.

For example, you have the class with the following properties:

    using DHTMLX.Scheduler;
    public class DataItem
    {
        public int EventId { get; set; }
        public string Description { get; set; }
        public DateTime start_date { get; set; }
        public DateTime end_date { get; set; }
    }

To load data as it is without changing the names of members (i.e. EventIdid, Descriptiontext), alter the code as in:

using DHTMLX.Scheduler;
public class DataItem
{
    [DHXJson(Alias = "id")]
    public int EventId { get; set; }
    [DHXJson(Alias = "text")]
    public string Description { get; set; }
 
    public DateTime start_date { get; set; }
    public DateTime end_date { get; set; }
}

Preventing data properties from sending to the client

Starting from version 3.0, you can exclude specific properties from ones that will be sent to the client.
To do this, use the [DHXJson(Ignore = 'true')] serialization attribute as in:

//the 'RelatedEvents' property won't be sent to the client
public class DataItem
{
    public int id { get; set; }
    public string text { get; set; }
    public DateTime start_date { get; set; }
    public DateTime end_date { get; set; }
    [DHXJson(Ignore=true)]
    public List<CalendarEvent> RelatedEvents { get; set; }
}

 
Note, you can 'ignore' the mandatory properties: 'id', 'text', 'start_date', 'end_date'.

Custom render function

By default, the built-in serializer renders all public data properties. If you want to render a part of properties or your data objects don't fit the stated data requirements you need to specify a custom render function.

How can you set a custom render function for data?

In most code samples we use the following technique for loading data:

public ContentResult Data()
{
      var data = new SchedulerAjaxData((new DHXSchedulerDataContext()).Events);
      return data;
}

But in reality, the code above is just a short variant of the following one:

public ContentResult Data()
{
      var data = new SchedulerAjaxData((new DHXSchedulerDataContext()).Events);
      return Content( data.Render() );
}

The SchedulerAjaxData.Render() method has 2 overloads:

  1. public string Render()
  2. public string Render(Action <System.Text.StringBuilder, object> renderer)
  • renderer - a custom function that renders event objects.

The first overload is used while standard loading data. The second allows specifying a custom render function (see a usage example below).

public ContentResult Data()
{
      var data = new SchedulerAjaxData((new DHXSchedulerDataContext()).Events);
      return Content( data.Render(eventRenderer) );
}
 
public void eventRenderer(System.Text.StringBuilder builder, object ev)
{
      var item = ev as Event;
      builder.Append(
                string.Format("{{id:{0}, text:\"{1}\", start_date:\"{2:MM/dd/yyyy HH:mm}\", end_date:\"{3:MM/dd/yyyy HH:mm}\"}}",
                item.id,
                HttpUtility.JavaScriptStringEncode(item.text),
                item.start_date,
                item.end_date));
}

While defining a custom function, please remember, that you need to escape characters that may break JSON(such as quotes, newlines, etc.). For this purpose you can use the HttpUtility.JavaScriptStringEncode utility (.Net 4.0+) as it's shown in the code above. If you use older version of .NET you should provide some custom solution.

Custom date format

If you set a custom value for the DHXScheduler.Config.xml_date configuration option in the Index() action, don't forget to set the same date format for the SchedulerAjaxData object.

public ActionResult Index(){
          ...          
          scheduler.Config.xml_date = "%d/%m/%Y %H:%i";
          ...
}
 
public ContentResult Data(){
          var events = (new DHXSchedulerDataContext()).Events;
          var data = new SchedulerAjaxData(events);
 
          data.DateFormat = "%d/%m/%Y %H:%i";
          return (data);
}

See available variations of the format string here.

Updating data from the server-side

When you need to update data depending on the result of a server-side operation you should do 2 things:

  1. To set the flag sched.Data.DataProcessor. UpdateFieldsAfterSave to true (in the Index() action).
  2. To set new values for properties in the response through the UpdateField(string fieldName, object fieldValue) method of the AjaxSaveResponse class (in the Save() action).


For example, you want to show events in different colors: events before the current date in gray, others - in blue.

So, you set the flag:

public ActionResult Index() {
  var sched = new DHXScheduler(this);
   ...
  sched.Data.DataProcessor.UpdateFieldsAfterSave = true;
   ...
  return View(sched);
}

and assign the needed color:

public ContentResult Save(ColoredEvent changedEvent, FormCollection actionValues) {
  var action = new DataAction(actionValues);
  var color = "";
  if (changedEvent.start_date < DateTime.Now)
         color = "gray";
  else
         color = "blue";
  ...
 
  var result = new AjaxSaveResponse(action);
  result.UpdateField("textColor", color);//adds a new value
  return result;
}

Loading custom data

You can provide SchedulerAjaxData response with additional data, which can be later accessed on the client-side. Additional items are added as named collections to the SchedulerAjaxData.ServerList dictionary:

var data = new SchedulerAjaxData();
data.Add(new List<object>{
    new { id = 1, text = "Event 1", start_date = new DateTime(2014, 12, 4, 10, 0, 0), end_date = new DateTime(2014, 12, 4, 12, 0, 0) },
    new { id = 2, text = "Event 2", start_date = new DateTime(2014, 12, 4, 13, 15, 0), end_date = new DateTime(2014, 12, 4, 14, 0, 0) },
    new { id = 3, text = "Event 3", start_date = new DateTime(2014, 12, 4, 13, 0, 0), end_date = new DateTime(2014, 12, 4, 13, 30, 0) },
});
 
data.ServerList.Add("dayoff", new List<object>{
    new { Date = new DateTime(2014, 11, 1)},
    new { Date = new DateTime(2014, 12, 14)}
});
 
return (ContentResult)data;

When such response is loaded to the page, the client-side component will fire onOptionsLoad event, followed by onXLE event.

The collection can be accessed on the client-side using scheduler.serverList method (JavaScript):

var dayoff = scheduler.serverList("dayoff");

Note, for correct work, server list has to be initialized on the client-side before loading. In order to do so, call scheduler.serverList(“listName”); before initialization of scheduler: C#:

var scheduler = new DHXScheduler();
scheduler.BeforeInit.Add("initServerLists();");

JS:

function initServerLists(){
   scheduler.serverList("dayoff");
}

Loading sections of the Timeline and Units

Scheduler supports loading Timeline and Units options by default. It can be done by setting a ServerList property of Timeline or Units instance: Initialization:

var scheduler = new DHXScheduler(this);
var timeline = new TimelineView("timeline", "section_id") { 
         RenderMode = TimelineView.RenderModes.Bar,
         X_Unit = TimelineView.XScaleUnits.Day,
         X_Size = 7,
         X_Date = "%d"
};
scheduler.Views.Add(timeline);
timeline.ServerList = "sections";

Loading options:

var data = new SchedulerAjaxData(events);
 
data.ServerList.Add("sections", new List<object>{
     new { key = "1", label = "Section 1" },
     new { key = "2", label = "Section 2" },
     new { key = "1", label = "Section 3" }
});

In this case no additional code is required. Timeline and Units views will fetch options from the lists with the names specified.

Handling errors

In case of network errors or invalid server response, the client-side will fire "onLoadError" event, which can be captured with a JavaScript code:

scheduler.attachEvent("onLoadError", function(resp){
    dhtmlx.message("The service is currently offline...");
});

See the event details here


comments powered by Disqus