Recurring events

Recurring events

recurring events in asp net calendar

By default, Scheduler doesn't support recurring events. So, to provide such functionality you should a little bit extend your existing code.

Model changes

Let's start from the model.

You should add 3 extra fields to database (as with reqular events, in addition to the mandatory fields you can retrieve any extra data from the database):

  1. event_length - (bigint) the time duration of an event in seconds;
  2. event_pid - (int) the parent id of a series of events. Particular occurrences refer to the the series through this id;
  3. rec_type - (nvarchar[64]) defines the repetition logic of a recurring event (e.g. each working day, the first Saturday of each 2 months). This field is filled in automatically. See details below.

Also note, fields start_date and end_date a little bit change their meaning:

  • start_date - (datetime) the start date of the first event in a series in the format 'yyyy-mm-dd hh:mm:ss'.
  • end_date - (datetime) the end date of the last event in a series in the format 'yyyy-mm-dd 00:00:00'.

And because start_date and end_date fields store the start and end dates of an event series (not a specific occurence), we need to have the event_length field to store the duration of a specific occurence.

To get detail information about presenting recurring events in the database, please, refer to the dhtmlxScheduler documentation - 'Server-side integration'.

Sample DB structure

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

  [id]           INT           IDENTITY (1, 1) NOT NULL,
  [text]         TEXT          NULL,
  [start_date]   DATETIME      NOT NULL,
  [end_date]     DATETIME      NOT NULL,
  [event_length] BIGINT        NULL,
  [rec_type]     NVARCHAR(50)  NULL,
  [event_pid]    INT           NULL,

Controller changes

In the controller you must enable the extension


and provide the following logic:

  • if an event with rec_type==none was inserted - the response must have “deleted” status;
  • if an event with rec_type!=none was updated or deleted - all records with the related event_pid must be deleted;
  • if an event with the event_pid value was deleted - it need to be updated with rec_type==none instead of deleting.
public ActionResult Save(int? id, FormCollection actionValues)
     var action = new DataAction(actionValues);
     DHXSchedulerDataContext data = new DHXSchedulerDataContext();
         var changedEvent = (Recurring)DHXEventsHelper.Bind(typeof(Recurring), actionValues); // takes the object of an event
         bool isFinished = deleteRelated(action, changedEvent, data);
         if (!isFinished)
              switch (action.Type)
                   case DataActionTypes.Insert:
                       if (changedEvent.rec_type == "none")//deletes one event from the series
                            action.Type = DataActionTypes.Delete;
                   case DataActionTypes.Delete:
                       changedEvent = data.Recurrings.SingleOrDefault(ev => == action.SourceId);
                   default:// "update"   
                       var eventToUpdate = data.Recurrings.SingleOrDefault(ev => 
              == action.SourceId);
                       DHXEventsHelper.Update(eventToUpdate, changedEvent, new List<string>() { "id" });
          action.TargetId =;
     catch (Exception a)
         action.Type = DataActionTypes.Error;
     return (new AjaxSaveResponse(action));
// when the series is changed or deleted we need to remove(change) all related events (events with the same 'event_pid') 
protected bool deleteRelated(DataAction action, Recurring changedEvent, DHXSchedulerDataContext context)
    bool finished = false;
    if ((action.Type == DataActionTypes.Delete || action.Type == DataActionTypes.Update)
            && !string.IsNullOrEmpty(changedEvent.rec_type))
        context.Recurrings.DeleteAllOnSubmit(from ev in context.Recurrings 
                                                  where ev.event_pid == select ev);
    if (action.Type == DataActionTypes.Delete 
           && (changedEvent.event_pid != 0 && changedEvent.event_pid != null))
        Recurring changed  = (from ev in context.Recurrings where == action.TargetId select ev)
           .Single() ;
        changed.rec_type = "none";
        finished = true;
    return finished;

Getting instances of recurring events

Recurring events aren't stored in the database as individual items. The db contains the start date, the time length and repetition of the series and based on this information events are rendered in scheduler.

In cases, when you need to get an array of single events within a specific interval you should use method List<object> GetOccurrences(IEnumerable source, DateTime from, DateTime to) of the helper DHTMLX.Common.DHXEventsHelper class. As parameters, the method takes collection of items, start and end dates (set the time interval you want to get instances of single events from).

var helper = new DHXEventsHelper();
var items = helper.GetOccurrences(new DHXSchedulerDataContext().Recurrings, new DateTime(2012, 11, 10), 
new DateTime(2012, 12, 10));

Format details

Client-side gets data from the rec_type field as a string of the following format: [type]_[count]_[count2]_[day]_[days]#[extra]

  • type - the type of repeation: 'day','week','month','year'.
  • count - the interval between events in the “type” units.
  • count2 and day - define a day of a month ( first Monday, third Friday, etc ).
  • days - the comma-separated list of affected week days.
  • extra - the extra info that can be used to change presentation of recurring details. It does't affect the real recurring pattern and is used to set the state of the recurring editor form.
    It may take next values:
    • “no” - the event without the end date ( infinite recurring )
    • {number} - the count of occurences

Examples of the rec_type data:

  • day_3___ - each three days
  • month _2___ - each two month
  • month_1_1_2_ - second Monday of each month
  • week_2___1,5 - Monday and Friday of each second week
  • none - a special value used when you delete a single event from the series. Such 'deleted' event isn't deleted from the database, it's just marked by the 'none' value to not be rendered in Scheduler.

Excluding past days from events with the 'weekly' recurrence

By default, an event with the 'weekly' recurrence contain occurrences starting from the first day of the week it has been created.
Such behavior can result in including past days (that are already gone) into the recurrence.

For example, the user creates an event on Friday, and specifies the 'weekly' repetition on Tuesday and Thursday. The stored event will contain the current week, i.e. past Tuesday and Thursday, even though it has been created on Friday.

Starting from version 3.0, the library provides a new configuration property DHXScheduler.Config.repeat_precise that allows excluding past days from the recurrence. Set the property to true and the start date of a recurring event will be the date of the first real occurrence, which in our example is Tuesday of the next week.

var sched = new DHXScheduler();
sched.Config.repeat_precise = true;

Customizing a form control for recurring events

Starting from Scheduler .NET version 3.2, you can redefine the layout of the recurring control.

How Can You Customize the Recurring Layout?

  • Change the form markup
  • Delete excess elements (e.g., the 'yearly' repeat type and all related inputs)
  • Set default values for inputs (e.g., you can set ‘no end date’ for recurring events and hide the block that specifies the recurrance end date).


Let's start with a use-case. Imagine that you need to remove the 'monthly' and 'yearly' repeat types and set the 'no end date' option for all events (i.e. remove the block that specifies the end of reccurance).

Step 1. Define the markup of custom form and put it somewhere on the page (start with copying the default template that can be found at 'dhtmlxScheduler\sources\locale\recurring\'):

<div style="display:none">
<div class="dhx_form_repeat" id="custom_form"> 
      <select name="repeat">
        <option value="day">Daily</option>
        <option value="week">Weekly</option>
      <div style="display:none;" id="dhx_repeat_day">
        <input type="hidden" name="day_type" value="d"/>
        <input type="hidden" name="day_count" value="1" />
      <div style="display:none;" id="dhx_repeat_week">
        Repeat every week next days:<br />
        <label><input type="checkbox" name="week_day" value="1" />Monday</label>
        <label><input type="checkbox" name="week_day" value="2" />Tuesday</label>
        <label><input type="checkbox" name="week_day" value="3" />Wednesday</label>
        <label><input type="checkbox" name="week_day" value="4" />Thursday</label>
        <label><input type="checkbox" name="week_day" value="5" />Friday</label>
        <label><input type="checkbox" name="week_day" value="6" />Saturday</label>
        <label><input type="checkbox" name="week_day" value="0" />Sunday</label>
        <input type="hidden" name="week_count" value="1" />
    <input type="hidden" value="no" name="end">

Set the Form property of the LightboxRecurringBlock control to the id of your custom form:

scheduler.Lightbox.Add(new LightboxRecurringBlock("recurring", "Repeat"){
    Form = "custom_form"

Main Parts

We have provided the default HTML structure of the lightbox's recurring block for different languages at the 'dhtmlxScheduler\sources\locale\recurring\' directory. For example, see the 'dhtmlxScheduler\sources\locale \recurring\repeat_template_en.htm' file for the English locale. In general, the recurring block of the lightbox consists of 3 groups of controls:

* Controls for choosing the recurrence type. These inputs have the name 'repeat' and one of the following values: 'dayly', 'weekly', 'monthly', 'yearly'. The form must have at least one 'repeat' input with a value. You can use radio buttons as in the case above, selects or set the default type in the hidden input. Consider the following examples, each of those is a valid way for selecting the type of recurrence in the form. Radio buttons:

<label><input type="radio" name="repeat" value="day" />Daily</label><br />
<label><input type="radio" name="repeat" value="week"/>Weekly</label><br />
<label><input type="radio" name="repeat" value="month" />Monthly</label><br />
<label><input type="radio" name="repeat" value="year" />Yearly</label>
Select input, without 'Monthly' and 'Yearly' options:
<select name="repeat">
  <option value="day">Daily</option>
  <option value="week">Weekly</option>

Hidden input (the lightbox will create only 'Dayly' series):

<input type="hidden" name="repeat" value="day" />

A block to configure the recurrence depending on the repeat type. For example, for the 'Daily' repeat type, the block will take the following structure:

<div class="dhx_repeat_center">
    <div style="display:none;" id="dhx_repeat_day">
            <input class="dhx_repeat_radio" type="radio" name="day_type" value="d"/>Every
        <input class="dhx_repeat_text" type="text" name="day_count" value="1" />day<br />
            <input class="dhx_repeat_radio" type="radio" name="day_type" checked value="w"/>Every workday

Note, that the markup that is related to the specific type of recurrence can be wrapped in a div with the id in the following format “dhx_repeat_<repeat type>“, e.g. “dhx_repeat_day”. In this case it will be displayed only when the appropriate repeat type is selected.

Controls for specifying the end of recurrence. The end of recurrence is defined by input with the name 'end'. Possible values are 'no', 'date_of_end', 'occurences_count'. Similar to the 'repeat' controls, the form must have at least one input of this type.

<div class="dhx_repeat_right">
    <input type="radio" name="end" value="no" checked/>No end date
  </label><br />
    <input type="radio" name="end" value="date_of_end" />After</label>
    <input type="text" name="date_of_end" />
  <br />
    <input type="radio" name="end" value="occurences_count" />After</label>
    <input type="text" name="occurences_count" value="1" />Occurences

The date for the 'date_of_end' mode must be defined in an input named 'date_of_end'. The same works for the 'occurences_count' mode, that takes the number of occurences from an input named 'occurences_count'. You can remove any type or predefine it in the hidden input:

<input type="hidden" name="end" value="date_of_end" />
<input type="hidden" name="date_of_end" value="01.01.2016" />

Notes for changing the recurring block

Please, before starting to apply a custom configuration to the lighbox's recurring block, consider the following things:

  • The 'name' attribute is hardcoded for all inputs - the inputs with different names will be ignored.
  • The 'value' attribute is fixed for all inputs except for ones that imply direct input.
  • When you specify a new form - dhtmlxScheduler doesn't use it directly and just replicates your HTML structure into the lightbox's template. It means that all event handlers or custom properties that have been attached to DOMElements of your form from the code won't be applied to the form in the lightbox. If you want to attach event handlers, you need to either specify it as an inline HTML attribute, or attach a handler to the form when it's shown in the lightbox.

Beware, dhtmlxScheduler doesn't work with your original HTML form and just creates its copy in the lightbox's template.

Will be copied to the lightbox:

<input onclick="handler()">

Won't be copied to the lightbox

addEventListener(node, "click", function(){...})

comments powered by Disqus