Event Calendar for ASP.NET MVC with dhtmlxScheduler

NOTE: We’re now offering DHTMLX Scheduler .NET, an optimized version for ASP.NET apps.

scheduler-in-blog-dhtmlx

This tutorial will lead you through the steps required to integrate dhtmlxScheduler into an ASP.NET MVC application. dhtmlxScheduler is a JavaScript scheduling calendar component, which can be used for a wide variety of use-cases connected to scheduling tasks. We will learn how to put this Ajax-based calendar on a web page, load events from .NET sever side and update them in the database when a user makes changes in the browser.

Download the final demo to get a better understanding of the solution we’re about to build.

scheduler-asp-net-flat

Modern web apps impose ever higher demands on the user interface. In the case of standard controls, you can always use a built-in solution. However, with more complex controls – a calendar UI, for example – you are up against the problem. But here, third-party solutions can help. One of them is dhtmlxScheduler.

Preparation

First of all, you need to create a new project. Nothing specific, just an empty ASP.NET MVC project. Name it, for example, “My Calendar”. After that, create a database (or use any valid one) where you will save the calendar events. In the database, create the table “Events” with the following set of fields (all fields are mandatory):

Field Type Description
id identity, primary key the ID of an event
text text the description of an event
start_date datetime the date and the time of an event start
end_date datetime the date and the time of an event end

 
While the DB tool is open, you can add some test data to the “Events” table. If you downloaded the final demo package, you can find there MyCalendar.mdf file which already contains the necessary table and data.

The next thing you need is the dhtmlxScheduler package, which can be downloaded from the dhtmlxScheduler homepage. Copy the content from the folder ‘codebase’ to the folder ‘Scripts’ of your project. The result of this step should look similar to the following:

dhtmlxScheduler Files

dhtmlxScheduler Files

Now that everything is ready, and all the necessary files are in place, you can proceed to the first step.

Step 1 – Initialization

First of all, you need to create a default view. Add a new controller – “CalendarController” – and create the “Index” view for it. Here is the content of Index.aspx file:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
<script src="/Scripts/dhtmlxscheduler.js" type="text/javascript"></script>
<link href="/Scripts/dhtmlxscheduler.css" rel="stylesheet" type="text/css" />
<style type="text/css">
html, body
{
height:100%;
padding:0px;
margin:0px;
}
</style>
<script type="text/javascript">
function init() {
scheduler.init("scheduler_here",new Date(2010,6,1),"month");
}
</script>
</head>
<body onload="init()">
<div id="scheduler_here" class="dhx_cal_container" style='width:100%; height:100%;'>
<div class="dhx_cal_navline">
<div class="dhx_cal_prev_button">&nbsp;</div>
<div class="dhx_cal_next_button">&nbsp;</div>
<div class="dhx_cal_today_button"></div>
<div class="dhx_cal_date"></div>
<div class="dhx_cal_tab" name="day_tab" style="right:204px;"></div>
<div class="dhx_cal_tab" name="week_tab" style="right:140px;"></div>
<div class="dhx_cal_tab" name="month_tab" style="right:76px;"></div>
</div>
<div class="dhx_cal_header">
</div>
<div class="dhx_cal_data">
</div>
</div>
</body>
</html>

The default view loads .js and .css files of the dhtmlxScheduler and initializes a full-screen scheduler. The second and third parameters in the ‘scheduler.init’ command define default date and mode, which will be in the calendar just after initialization. Except for the first line, the code doesn’t have anything .NET MVC-specific. Actually, it’s fully taken from a standard scheduler example.

Now one more thing needs to be done – the updating of a default route. Switch the default route of the app to the newly-created controller in Global.asax.cs:

public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Calendar", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}

When all this is done and correct, you can run the app and see the next screen:

Scheduler on page

Scheduler on page

If you don’t see the screen above, most probably you didn’t copy the scheduler’s files to the folder ‘Scripts’ correctly, so check it again.

The calendar created with the dhtmlxScheduler has a clean and intuitive interface, and managing events is quite easy. To create new events, use the double click or click-and-drag commands. By clicking on tabs in the upper right-hand corner you can switch views: Day, Week, or Month.

Step 2 – Loading Data

The view we constructed in the previous step looks fine, but it doesn’t contain any data, so now let’s change this. First, add ‘Model’ to your application (just use “Model > Add > Add new item” and select “Data”,”Linq to SQL Classes”). To complete the process, drag-and-drop the “Events” table to the Model Designer, and then add one more action to the CalendarController.cs:

public ActionResult Data()
{
MyEventsDataContext data = new MyEventsDataContext();
return View(data.Events);
}

Define view for that action – Data.aspx:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" ContentType="text/xml" %>
<data>
<% foreach (var myevent in Model) { %>
<event id="<%=myevent.id%>">
<start_date><![CDATA[<%= String.Format("{0:MM/dd/yyyy HH:mm}",myevent.start_date) %>]]></start_date>
<end_date><![CDATA[<%= String.Format("{0:MM/dd/yyyy HH:mm}",myevent.end_date) %>]]></end_date>
<text><![CDATA[<%= myevent.text%>]]></text>
</event>
<% } %>
</data>

This template outputs not HTML, but XML data. For each event it will output a block of XML data. An extra bit of code is used to provide data in the necessary format. If you need to add extra fields to the model, just add extra tags to the view.

Slightly adjust the initialization code of your scheduler in Index.aspx:

<script type="text/javascript">
function init() {
scheduler.config.xml_date = "%m/%d/%Y %H:%i"; // format of dates in XML
scheduler.init("scheduler_here", new Date(2010, 6, 1), "month");
scheduler.load("/Calendar/Data");  //path to the newly created action
}
</script>

Well, you’ve just configured the format of dates (it’s the same as in Data.aspx) and defined the path to action ‘Data’. At this point, the running application will look like this:

Scheduler - Loading the events

Scheduler - Loading the events

We’re halfway there. Just one more step, and we’re almost done.

Step 3 – Saving to the Database

After all the manipulations described above, we’ve built a scheduler which loads the events data from the database, but that’s not enough. Our next goal is to save changes made on the client side to the server. First of all, create one more action – CalendarController.cs:

public ActionResult Save(FormCollection actionValues)
{
String action_type = actionValues["!nativeeditor_status"];
Int64 source_id = Int64.Parse(actionValues["id"]);
Int64 target_id = source_id;

MyEventsDataContext data = new MyEventsDataContext();
Event myevent;
try{
switch (action_type)
{
case "inserted":
myevent = new Event();
myevent.start_date = DateTime.Parse(actionValues["start_date"]);
myevent.end_date = DateTime.Parse(actionValues["end_date"]);
myevent.text = actionValues["text"];
data.Events.InsertOnSubmit(myevent);
break;
case "deleted":
myevent = data.Events.SingleOrDefault(ev => ev.id == source_id);
data.Events.DeleteOnSubmit(myevent);
break;
default: // "updated"
myevent = data.Events.SingleOrDefault(ev => ev.id == source_id);
myevent.start_date = DateTime.Parse(actionValues["start_date"]);
myevent.end_date = DateTime.Parse(actionValues["end_date"]);
myevent.text = actionValues["text"];
break;
}
data.SubmitChanges();
target_id = myevent.id;
}
catch
{
action_type = "error";
}

return View(new CalendarActionResponseModel(action_type, source_id, target_id));
}

It seems that we have a lot of code, but it’s quite simple in its logic. In the first lines, we specify the type of action from the incoming request. Then, depending on the type, we inserted, deleted, or updated the data in the database. And after the DB operation was completed, we rendered a response to the client-side scheduler.

The file Save.aspx will look like this:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<scheduler.ActionResponseModel>" ContentType="text/xml"%>
<data>
<action type="<%= Model.Status %>" sid="<%= Model.Source_id %>" tid="<%= Model.Target_id %>"></action>
</data>

The view shown above uses class ‘CalendarActionResponseModel’ to transfer the necessary information from the action to the view. In CalendarController.cs we add:

public class CalendarActionResponseModel
{
public String Status;
public Int64 Source_id;
public Int64 Target_id;
public CalendarActionResponseModel(String status, Int64 source_id, Int64 target_id)
{
Status = status;
Source_id = source_id;
Target_id = target_id;
}
}

Now update the Index.aspx one more time (add code that will link updates on the client-side scheduler with the action ‘Save’) :

<script type="text/javascript">
function init() {
scheduler.config.xml_date = "%m/%d/%Y %H:%i";
scheduler.init("scheduler_here", new Date(2010, 6, 1), "month");
scheduler.load("/Calendar/Data");

var dp = new dataProcessor("/Calendar/Save");
dp.init(scheduler);
dp.setTransactionMode("POST", false);
}
</script>

If you launch the app now, the screen will look similar to the one from Step 2, but any changes or new events will be saved to the DB. Also, it will correctly restore after page reloading. So now we can proceed to the last step.

Step 4 – Improvements

The code we are using in ‘SaveController’ can be improved by using automatic bindings. In CalendarController.cs:

public ActionResult Save(Event changedEvent, FormCollection actionValues)
{
String action_type = actionValues["!nativeeditor_status"];
Int64 source_id = Int64.Parse(actionValues["id"]);
Int64 target_id = source_id;
MyEventsDataContext data = new MyEventsDataContext();
try{
switch (action_type)
{
case "inserted":
data.Events.InsertOnSubmit(changedEvent);
break;
case "deleted":
changedEvent = data.Events.SingleOrDefault(ev => ev.id == source_id);
data.Events.DeleteOnSubmit(changedEvent);
break;
default: // "updated"
changedEvent = data.Events.SingleOrDefault(ev => ev.id == source_id);
UpdateModel(changedEvent);
break;
}
data.SubmitChanges();
target_id = changedEvent.id;
}
catch
{
action_type = "error";
}
return View(new CalendarActionResponseModel(action_type, source_id, target_id));
}

To give your calendar a slicker and glossier look, or to customize the color scheme, use the online Skin Builder for dhtmlxScheduler [deprecated]. Select one of “Glossy” skins to get a more modern look for the calendar. When you’re done with the customization, download the skin package (.css files and images), and unpack it in the folder ‘‘Scripts’ (it will overwrite some old scheduler files).

The running app after those updates will produce the final look:

Scheduler - Glossy skin

Scheduler - Glossy skin

So let’s see what we’ve got: in just a few steps, we have implemented a web-based calendar that can be used in ASP.NET MVC and provide all the necessary functions: loading, saving, deleting, and updating events.

Of course, perfection knows no bounds. You can define extra fields, add/move calendar views, or redefine the scale and templates configuration (please refer to dhtmlxScheduler documentation). All these changes can be made simply by adding extra JavaScript commands in the “Index” view. There is no need for further updates in the “CalendarController.cs” code. So turn on your imagination and get going!

NOTE: If you’re using VB, please read this comment (many thanks to Brian).

Posted by Ivan Petrenko

Advance your web development with DHTMLX

Gantt chart
Event calendar
Diagram library
30+ other JS components