Well this is a blog entry on request (the request is here). I received a request couple of days ago on one of my earlier ExtJs Calendar Component related posts to demonstrate remote Calendar CRUD operations in Ext.Net. So Gayan (the requestor), here goes the reply.

To begin with, Ext.Net ships with the Community version of the Calendar Component, which although being powerful, is limited when you compare it with the advanced features available in the Pro version of the Calendar Component. If you are not already aware, the Calendar Component has been donated to ExtJs by a company called Extensible owned by Brian Moeskau. Brian is one of the original developers for the ExtJs toolkit (that explains the beauty and power of the Calendar Component, Brian knows ExtJs inside out).

I have found the community version lacking for my needs, so I use the Pro version of the Calendar component outside the Ext.Net framework.

This link from Brian himself provides a good introduction to the Calendar functionality and is a must-read if you are using the Calendar component for the first time. Documentation for the component can be “cloned” from the official GitHub repository for the Calendar component here.

Gayan’s request actually had 2 parts:

  1. Is it possible to have custom fields for the EventStore.

    The answer is yes. Calendar component’s EventStore (and CalendarStore) are designed to be extensible. They expect some fields that should always be present (e.g. Id, Start time, End time and Title etc. for each Event). You are free to add any number of additional fields to the EventStore but you need to take care that the required fields are always present.

    Further you are allowed to rename the required fields by defining custom mappings. See the example below that should explain the process:

    var EM = Ext.calendar.EventMappings;
    EM.EventId.name = 'id';
    EM.CalendarId.name = 'cid';
    EM.Title.name = 'subject';
    EM.Notes.name = 'body';
    EM.StartDate.name = 'start';
    Ext.calendar.EventRecord.reconfigure(); 

    I have renamed the required fields above by defining custom mappings, and now I can add fields “id”, “cid”, “subject” etc. to the EventStore and any other custom fields I require.

    The custom mappings need to be defined after the Calendar scripts are loaded but BEFORE the EventStore is instantized. See the attached files for an example demonstrating how this can be done.

    In case of Ext.Net, it automatically adds the default Event Store fields, you need to set StandardFields=”false” on the Event Store and then add the desired fields in the appropriate Reader. the attached code demonstrates all this. Please note that the attached code shows all fields that CalendarPanel supports, and can be renamed. You can add additional fields, but do not try to configure Mappings for the additional fields because that is not needed.

    Similar functionality is available for CalendarStore also, but only in the Pro version. You cannot rename/remap Calendar Store fields in the community version of the Calendar Component.

  2. The second part of the request is demonstration of the CRUD operations. Well, this part should have been easy if you have ever used HttpProxy for a RestFul ExtJs Store. Any actions against the Calendar component would have been posted to the handler automatically. Not to worry, let me quickly take you through the process.

    To begin with, you define a Store with a properly configured HttpProxy. Here’s an example:

    <EventStore runat="server" ID="storeEvents" StandardFields="false" DateFormat="Y-m-dTh:i:s" AutoSave="true" Restful="true">
    	<Reader>
    		<ext:JsonReader IDProperty="id" Root="data" SuccessProperty="success" MessageProperty="message">
    			<Fields>
    				<ext:RecordField Name="id" />
    				<ext:RecordField Name="cid" />
    				<ext:RecordField Name="subject" />
    				<ext:RecordField Name="body" />
    				<ext:RecordField Name="start" Type="Date" />								
    				<ext:RecordField Name="end" Type="Date" />
    				<ext:RecordField Name="allDay" Type="Boolean" />
    				<ext:RecordField Name="reminderMinutes" />
    				<ext:RecordField Name="location" />
    				<ext:RecordField Name="url" />
    			</Fields>
    		</ext:JsonReader>
    	</Reader>
    	<Proxy>
    		<ext:HttpProxy Method="POST">
    			<RestAPI CreateUrl="CalendarHandler.ashx?op=add" ReadUrl="CalendarHandler.ashx?op=get"
    					DestroyUrl="CalendarHandler.ashx?op=delete" UpdateUrl="CalendarHandler.ashx?op=update" UpdateMethod="POST" />
    		</ext:HttpProxy>
    	</Proxy>
    </EventStore>

    Next you need to handle some standard events on the CalendarPanel (you can in fact handle these events at many places, in CalendarPanel, in CalendarView, in EventEditWindow, in EventEditForm and in EventStore itself, but I will recommend hooking to CalendarPanel events because events fired by all other components are automatically routed to and relayed by CalendarPanel). Here’s the code for necessary event handling:

    {syntaxhighlighter brush: xml;fontsize: 100; first-line: 1; }<Listeners>
    <DayClick Handler=”showEditWindow(this, {start: dt, allDay: allDay}, el);” />
    <EventClick Handler=”showEditWindow(this, record, el);” />
    <EventMove Handler=”record.commit();” />
    <ViewChange Handler=”if(this.editWin)this.editWin.hide();” />
    <RangeSelect Handler=”
    showEditWindow(this, dates);
    this.editWin.on(‘hide’, callback, this, {single:true});” />
    <EventResize Handler=”record.commit();” />
    <EventDelete Handler=”this.eventStore.delete(record);” />
    </Listeners>{/syntaxhighlighter}
    Finally, you write your server-side handler for responding to CalendarPanel Ajax calls. Here’s the prototype for the Handler’s code:

    {syntaxhighlighter brush: csharp;fontsize: 100; first-line: 1; }switch (context.Request[“op”])
    {
    case “get”:
    //You need to return data based on “start” and “end” parameters from Request. Use Fiddler to analyze how they are passed and then return the data appropriately.
    var l=new System.Collections.Generic.List<object>();
    l.Add(new { id = 1, cid = 1, subject = “Meeting with Boss”, start = DateTime.Now.AddDays(-5).ToString(“s”), end = DateTime.Now.AddDays(-4.5).ToString(“s”), reminderMinutes = 30, location = “Office Canteen” });
    l.Add(new { id = 2, cid = 2, subject = “Picnic”, start = DateTime.Now.AddDays(2).ToString(“s”), end = DateTime.Now.AddDays(4).ToString(“s”), reminderMinutes = 30, location = “Office Canteen” });
    l.Add(new { id = 3, cid = 1, subject = “Another event”, start = DateTime.Now.AddDays(5.7).ToString(“s”), end = DateTime.Now.AddDays(6.9).ToString(“s”), reminderMinutes = 0, location = “Office Canteen” });

    context.Response.Write(serializer.Serialize(new { data = l }));
    break;

    case “add”:
    //Add record to database here.
    //Server must return id property of new record, I am returning a dummy value.
    //Also ensure to return all submitted data back to the client

    //The code below just extracts the data from the request and sends it back to the client with a random id.
    System.Collections.Generic.Dictionary<string,object> obj=serializer.Deserialize<System.Collections.Generic.Dictionary<string, object>>(context.Request[“data”]);
    obj[“id”] = DateTime.Now.Ticks % 1000;
    context.Response.Write(serializer.Serialize(new
    {
    success = true,
    data = obj
    }));

    //For errors, the you should return the following and handle Store’s exception event on client.
    //context.Response.Write(serializer.Serialize(new
    //{
    // success = false,
    // message = “Reason why it failed…”
    //}));
    break;

    case “update”:
    //Update data to db here. Again Fiddler should be your friend in case you are not sure what’s gets passed-in from client.
    context.Response.Write(serializer.Serialize(new
    {
    success = true
    }));
    break;

    case “delete”:
    //Delete record from db here. Again Fiddler should be your friend in case you are not sure what’s gets passed-in from client.
    context.Response.Write(serializer.Serialize(new
    {
    success = true
    }));
    break;
    }{/syntaxhighlighter}

The completely functional and working demonstration of the CRUD operations for the CalendarPanel together with examples of modifying the field names for the EventStore is attached with this post below. There are a couple of files, Calendar.aspx contains all the front-end markup and code required for handling CalendarPanel in Ext.Net, CalendarHandler.ashx is the backend code for the CalendarPanel CRUD operations.

If you are a native ExtJs user, you can find a fully functional demo for remote CRUD operations for the CalendarPanel in its GitHub repository link posted above.

I hope this blog post tells you everything you need to know for working with CalendarPanel Gayan…