Recurring events are a common feature in event calendar applications, allowing users to create events that repeat at specified intervals. Starting from v7.1 the Scheduler uses RFC-5545 based format for recurring events.
This article will explain how to use recurring events in the Scheduler and how to store them in the database.
You can find the description of the legacy format of recurring events here
By default, Scheduler doesn't support recurring events. To provide such a support, you need to enable a special extension on the page - recurring:
scheduler.plugins({
recurring: true
});
Once the support for recurring events is activated, the lightbox starts looking as shown below:
The library provides the following option to configure recurring events:
scheduler.config.repeat_date = "%m/%d/%Y";
...
scheduler.init('scheduler_here', new Date(2019, 7, 5), "month");
Related sample: Recurring events
By default, once the recurring extension is enabled, the lightbox starts to have one more section - "Repeat event". And the default definition of the 'recurring' lightbox starts to be as in:
[
{name:"description", height:130, map_to:"text", type:"textarea" , focus:true},
{name:"recurring", height:115, type:"recurring", map_to:"rec_type",
button:"recurring"},
{name:"time", height:72, type:"time", map_to:"auto"}
];
You may add any extra sections, but need to preserve both the "recurring" and "time" sections. Also, it's required to place the "time" section after the "recurring" one.
Related sample: Recurring events
A recurring event is stored in the database as a single record that contains all fields of a regular event plus several additional properties:
rrule follows the iCalendar format as specified in RFC-5545, detailing the frequency, interval, and other parameters that control the recurrence pattern.
Our format differs from the iCalendar format in the two key moments:
In the iCalendar format, the start and end dates of a recurring series are typically included as a part of the RRULE string as STDATE and DTEND properties. In our format, stdate and dtend are stored as separate fields. This separation allows for easier manipulation and querying of recurring events by date without the need to parse the RRULE string.
Here is an example of the recurring event series which is set to repeat every Monday starting from June 1, 2024 up until December 1, 2024:
{
"id": 1,
"text": "Weekly Team Meeting",
"start_date": "2024-06-03 09:00:00",
"duration": 3600,
"end_date": "2024-12-02 10:00:00",
"rrule": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO",
"recurring_event_id": null,
"original_start": null
}
Exceptions, also referred to as modified or deleted occurrences of the series, are stored as separate event records that are linked to their parent series. Exceptions have three additional properties: recurring_event_id, original_start, and deleted. These properties allow us to identify modified or deleted instances and their relationship to the parent series easily.
Note, that unlike the traditional iCalendar format, exceptions (modified or deleted instances) are not stored in the EXDATE property of the RRULE of the series.
Here is the example of the recurring series with one modified and one deleted occurrence:
[
{
"id": 1,
"text": "Weekly Team Meeting",
"start_date": "2024-06-03 09:00:00",
"duration": 3600,
"end_date": "2024-12-02 10:00:00",
"rrule": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO",
"recurring_event_id": null,
"original_start": null
},
{
"id": 2,
"text": "Special Team Meeting",
"start_date": "2024-06-10 09:00:00",
"end_date": "2024-06-10 11:00:00",
"rrule": null,
"recurring_event_id": 1,
"original_start": "2024-06-10 09:00:00"
},
{
"id": 3,
"text": "Deleted Team Meeting",
"start_date": "2024-06-17 09:00:00",
"end_date": "2024-06-17 10:00:00",
"rrule": null,
"recurring_event_id": 1,
"original_start": "2024-06-17 09:00:00",
"deleted": true
}
]
The repeated event scheduled for 2024-06-10 09:00:00
will be replaced with Special Team Meeting
record, and the event scheduled for 2024-06-17 09:00:00
will be skipped.
Note, that rrule of the modified or deleted occurrences is ignored.
text, start_date, and end_date of deleted instances are also ignored and the values of these fields won't affect the behavior of the Scheduler.
There is a possibility to delete or edit a particular occurrence in a series.
In addition to extra fields, a specific logic needs to be added to the server-side controller:
You can find the complete code examples here
Starting from version 4.2, dhtxmlScheduler allows you to specify a custom HTML form for the 'recurring' block of the lightbox.
Let's start with an example. Imagine that you want to remove the 'monthly' and 'yearly' repeat types and have the 'no end date' option for all events (i.e. remove the block for specifying the recurrence end).
<div class="dhx_form_repeat" id="my_recurring_form"> <form>
<div>
<select name="repeat">
<option value="day">Daily</option>
<option value="week">Weekly</option>
</select>
</div>
<div>
<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>
<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" />
</div>
</div>
<input type="hidden" value="no" name="end">
</form>
</div>
scheduler.config.lightbox.sections = [
{name:"description", height:130, map_to:"text", type:"textarea" , focus:true},
{name:"recurring", type:"recurring", map_to:"rec_type", button:"recurring",
form:"my_recurring_form"}, {name:"time", height:72, type:"time", map_to:"auto"}
];
You can find the default HTML structure of the lightbox's recurring block for different languages at the 'scheduler\sources\locale\recurring\' directory.
For example, for the English locale you need to check the 'scheduler\sources\locale\recurring\repeat_template_en.htm' file.
Basically, the recurring block of the lightbox contains 3 groups of controls:
1) Controls for choosing the type of recurrence. These inputs have the 'repeat' name and one of the following values: 'daily', 'weekly', 'monthly', 'yearly'. The form must have at least one 'repeat' input with a value. You can use radio buttons, selects or set the default type in the hidden input.
Consider the following examples, each of them is a valid way for selecting the type of recurrence in the form.
<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 name="repeat">
<option value="day">Daily</option>
<option value="week">Weekly</option>
</select>
<input type="hidden" name="repeat" value="day" />
2) A block for configuring 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">
<label>
<input class="dhx_repeat_radio" type="radio"
name="day_type" value="d"/>Every
</label>
<input class="dhx_repeat_text" type="text"
name="day_count" value="1" />day<br>
<label>
<input class="dhx_repeat_radio" type="radio"
name="day_type" checked value="w"/>Every workday
</label>
</div>
...
</div>
Note, that the markup which is related to a 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.
3) Controls for specifying the end of recurrence. The end of recurrence is defined by the input with the 'end' name.
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">
<label>
<input type="radio" name="end" value="no" checked/>No end date
</label><br />
<label>
<input type="radio" name="end" value="date_of_end" />After</label>
<input type="text" name="date_of_end" />
<br />
<label>
<input type="radio" name="end" value="occurences_count" />After</label>
<input type="text" name="occurences_count" value="1" />Occurrences
</div>
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 occurrences from an input named 'occurences_count'.
You can remove any type or predefine it in a hidden input:
<input type="hidden" name="end" value="date_of_end" />
<input type="hidden" name="date_of_end" value="01.01.2024" />
Please, before starting to apply a custom configuration to the lightbox's recurring block, note the following things:
Beware, dhtmlxScheduler doesn't work with your original HTML form and just creates its copy in the lightbox's template.
For example:
<input onclick="handler()">
addEventListener(node, "click", function(){...})
Until v7.1 Scheduler used a custom format for recurring events, you can find the format details here.
Back to top