dhtmlxScheduler loads data via ajax and can send create/update/delete changes back to the specified backend handler. Since the component does not provide automated database binding, such backend has to be implemented manually.
Below we'll show a common CRUD template for ASP.NET MVC and ASP.NET Web Forms. The explanation is provided afterwards.
public class CalendarController : Controller
{
public ActionResult Index()
{
var scheduler = new DHXScheduler(this);
// ajax call for Data on loading
scheduler.LoadData = true;
// send changes to the Save action
scheduler.EnableDataprocessor = true;
return View(scheduler);
}
public ContentResult Data()
{
var data = new SchedulerAjaxData(
new List<CalendarEvent>{
new CalendarEvent{
id = 1,
text = "Sample Event",
start_date = new DateTime(2017, 09, 03, 6, 00, 00),
end_date = new DateTime(2017, 09, 03, 8, 00, 00)
},
new CalendarEvent{
id = 2,
text = "New Event",
start_date = new DateTime(2017, 09, 05, 9, 00, 00),
end_date = new DateTime(2017, 09, 05, 12, 00, 00)
}
}
);
return (ContentResult)data;
}
public ContentResult Save(int? id, FormCollection actionValues)
{
var action = new DataAction(actionValues);
try
{
var changedEvent = DHXEventsHelper.Bind<CalendarEvent>(actionValues);
switch (action.Type)
{
case DataActionTypes.Insert:
// do insert
// action.TargetId = changedEvent.id; // assign database id
break;
case DataActionTypes.Delete:
// do delete
break;
default: // "update"
// do update
break;
}
}
catch
{
action.Type = DataActionTypes.Error;
}
return (ContentResult)new AjaxSaveResponse(action);
}
}
public partial class _Default : System.Web.UI.Page
{
public DHXScheduler Scheduler { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
this.Scheduler = new DHXScheduler();
Scheduler.DataAction = this.ResolveUrl("~/Data.ashx");
Scheduler.SaveAction = this.ResolveUrl("~/Save.ashx");
Scheduler.LoadData = true;
Scheduler.EnableDataprocessor = true;
}
}
ASPX
<div style="height:600px; width: 100%;">
<%= this.Scheduler.Render()%>
</div>
Data.ashx.cs
public class Data : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var data = new SchedulerAjaxData(
new List<CalendarEvent>{
new CalendarEvent{
id = 1,
text = "Sample Event",
start_date = new DateTime(2017, 09, 03, 6, 00, 00),
end_date = new DateTime(2017, 09, 03, 8, 00, 00)
},
new CalendarEvent{
id = 2,
text = "New Event",
start_date = new DateTime(2017, 09, 05, 9, 00, 00),
end_date = new DateTime(2017, 09, 05, 12, 00, 00)
}
}
);
context.Response.ContentType = "text/json";
context.Response.Write(data.ToString());
}
public bool IsReusable { get { return false; } }
}
Save.ashx.cs
public class Save : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
var action = new DataAction(context.Request.Form);
try
{
var changedEvent = DHXEventsHelper.Bind<CalendarEvent>(context.Request.Form);
switch (action.Type)
{
case DataActionTypes.Insert:
//do insert
//action.TargetId = changedEvent.id; // assign database id
break;
case DataActionTypes.Delete:
//do delete
break;
default:// "update"
//do update
break;
}
}
catch
{
action.Type = DataActionTypes.Error;
}
context.Response.ContentType = "text/xml";
context.Response.Write(new AjaxSaveResponse(action).ToString());
}
public bool IsReusable { get { return false; } }
}
The Data handler is covered in a separate article. Let's consider the Save handler.
As you can see, inside the Index action we create scheduler and tell it to load data:
var scheduler = new DHXScheduler(this);
scheduler.EnableDataprocessor = true;
And the Save action serves as a handler for changes made in the calendar.
What do we need to know now:
Specifying a different action:
var scheduler = new DHXScheduler(this);
scheduler.SaveAction = "SaveChanges";
scheduler.EnableDataprocessor = true;
Specifying a complete URL explicitly:
var scheduler = new DHXScheduler(); // !! use the default constructor
scheduler.SaveAction = Url.Content("~/data.ashx");
scheduler.EnableDataprocessor = true;
1) To parse a request, you should use the DHTMLX.Common.DataAction class.
DataAction properties are:
The last two parameters are different just in the case of the insert operation. In this case SourceID is the id generated on the client side and TargetId is the id of an event in the database.
2) To render the response, you should use the DHTMLX.Common.AjaxSaveResponse class. The constructor of AjaxSaveResponse takes a DataAction object as an argument.
By default, the DHTMLX.Common.DataAction class expects the item id to have the Integer type. But if you need, you can use other types, such as String or Guid.
To set a class different from Integer for the ID field, you should use generic of the DataAction class:
var action = new DataAction<string>(actionValues);
The library provides special helpers (the DHTMLX.Common.DHXEventsHelper class) that especially can come in use when you develop a usual .NET project (but for MVC projects they are also helpful).
So, these helpers are:
One more member of the class is the GetOccurrences() method. It's used for recurring events, and you can find details on it in the related article - Recurring events.
The Bind() method has 4 overloads:
As parameters the method takes:
The Update() method has 2 overloads:
As parameters the method takes:
With the helpers, the function implementing CRUD logic may look as follows:
Using LinqToSQL Data context
public ContentResult Save(int? id, FormCollection actionValues)
{
var action = new DataAction(actionValues);
var data = new DHXSchedulerDataContext();
try
{
var changedEvent = DHXEventsHelper.Bind<Event>(actionValues);
switch (action.Type)
{
case DataActionTypes.Insert:
data.Events.InsertOnSubmit(changedEvent);
break;
case DataActionTypes.Delete:
changedEvent = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
data.Events.DeleteOnSubmit(changedEvent);
break;
default:// "update"
var eventToUpdate = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
DHXEventsHelper.Update(eventToUpdate, changedEvent, new List() { "id" });
break;
}
data.SubmitChanges();
action.TargetId = changedEvent.id;
}
catch (Exception a)
{
action.Type = DataActionTypes.Error;
}
return (new AjaxSaveResponse(action));
}
Using Entity Framework context
public ContentResult Save(int? id, FormCollection actionValues)
{
var action = new DataAction(actionValues);
var changedEvent = DHXEventsHelper.Bind<Event>(actionValues);
var db = new CalendarContext();
try
{
switch (action.Type)
{
case DataActionTypes.Insert:
db.Events.Add(changedEvent);
break;
case DataActionTypes.Delete:
changedEvent = db.Events.FirstOrDefault(ev => ev.id == action.SourceId);
db.Events.Remove(changedEvent);
break;
default:// "update"
var target = db.Events.Single(e => e.id == changedEvent.id);
DHXEventsHelper.Update(target, changedEvent, new List<string> { "id" });
break;
}
db.SaveChanges();
action.TargetId = changedEvent.id;
}
catch (Exception a)
{
action.Type = DataActionTypes.Error;
}
return (new AjaxSaveResponse(action));
}
Helpers is a preferable approach, but if you don't want to use them, you can implement the CRUD logic by using MVC Model Binding:
// Using Linq To Sql context
public ContentResult Save(Event changedEvent, FormCollection actionValues)
{
// initializes a DataAction object from request parameters
var action = new DataAction(actionValues);
var data = new DHXSchedulerDataContext();
// Implementing create/update/delete operations.
// Note, we use the try-catch block to handle exceptions which may be thrown during operations.
// In this case, we must assign the error status to the DataAction object
// in order to mark the appropriate action on the client side as failed.
try
{
switch (action.Type)
{
case DataActionTypes.Insert:
data.Events.InsertOnSubmit(changedEvent);
break;
case DataActionTypes.Delete:
changedEvent = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
data.Events.DeleteOnSubmit(changedEvent);
break;
default:// "update"
changedEvent = data.Events.SingleOrDefault(ev => ev.id == action.SourceId);
UpdateModel(changedEvent);
break;
}
data.SubmitChanges();
action.TargetId = changedEvent.id;
}
catch (Exception a)
{
action.Type = DataActionTypes.Error;
}
// renders a response using an AjaxSaveResponse object. AjaxSaveResponse can be initialized by
// the DataActionResult object and can be implicitly converted
// to the System.Web.Mvc.ContentResult type.
return (new AjaxSaveResponse(action));
}
There is a possibility to set custom initial values for the event's properties. So, in cases when the user adds a new event, it will have values set by you.
To set custom initial values for new events, you should use the DHXScheduler.InitialValues.Add(string propertyName, object defaultValue) method. The DHXScheduler.InitialValues class contains a collection of default values for an event.
For example, if you want to change the text of new events and have "I'm your new event!" instead of "New event" you can call the Add() method as in:
var scheduler = new DHXScheduler()
scheduler.InitialValues.Add("text", "I'm your new event!");
In this part we'll consider how you can update a property or several properties on the client after saving a data item on the server.
First of all, to be able to update separate properties apart from the whole data item, you should activate a special mode (that provides such an ability), as in:
public ActionResult Index()
{
var scheduler = new DHXScheduler(this);
...
scheduler.UpdateFieldsAfterSave(); // this line activates the required mode
...
}
Then to update the desired property(-ies), you should use one of the methods below (the methods belong to the AjaxSaveResponse class):
public ContentResult Save(int? id, FormCollection actionValues)
{
...
var response = new AjaxSaveResponse(action);
response.UpdateField("propertyName", propertyValue);
return (ContentResult)response;
}
After the client gets the response from the server, it will update the 'propertyName' property of the modified data item with the value of 'propertyValue'.
public ContentResult Save(int? id, FormCollection actionValues)
{
...
var response = new AjaxSaveResponse(action);
response.UpdateFields(new Dictionary<string,object>{
{"propertyName", "propertyValue"},
{"propertyName2", "propertyValue2"}
};
return (ContentResult)response;
}
In case of network errors or invalid server response, the client side will fire the "onSaveError" event which can be captured with a JavaScript code:
scheduler.attachEvent("onSaveError", function(id, resp){
dhtmlx.message("Failed to update data");
})
See the event details here.
The component can work with the REST backend, which means that it can use an appropriate verb for each type of the operation - GET, POST, PUT, DELETE.
This mode can be enabled by the DHXScheduler.AjaxMode property:
var scheduler = new DHXScheduler();
scheduler.AjaxMode = TransactionModes.REST;