I want to share with you my solution how to prevent events overlapping in Out-Of-The-Box SharePoint Calendar.
As you know you can easly create client or server-side validator for simple (non-recurring) events. But for recurring events we have to check a lot more different options depends on what type of recurring events we have (daily, weekly, monthly, …), repetition pattern, how many repetition we want (date range) etc.

I have decided for server-side solution with web service which is called from JavaScript event function on Save button in New/Edit Form of SharePoint Calendar.
In web service we have two functions:
- SejneSobe_PreveriPrekrivanje which is called when we want to add simple (non-recurring) event and we want to check conflict with other events (recurring or non-recurring)
- SejneSobe_PreveriPrekrivanjePonavljajoce which is called when we want to add recurring event and we want to check conflict with other events (recurring or non-recurring)

You can see content of both function on my GitHub (link at the end of this blog post).
Then we have to modify New and Edit Form of our SharePoint Calendar list template where we have to include custom JS script files:
- SejneSobe_NewForm.js in New Form of SharePoint Calendar
- SejneSobe_EditForm.js in Edit Form of SharePoint Calendar
In both we have to remember original save button click handler for later use and we have to set new one (in my case) named CheckOverload().
var originalSaveButtonClickHandler = function () {
};
$(document).ready(function () {
var saveButton = $("[name$='diidIOSaveItem']");
if (saveButton.length > 0) {
originalSaveButtonClickHandler = saveButton[0].onclick;
}
$(saveButton).attr("onClick", "CheckOverload()");
});
In CheckOverload function we have to firstly check if we want to add recurrence or non-recurrence event. If is recurrence event, we call SejneSobe_PreveriPrekrivanjePonavljajoce function from web service otherwise we call SejneSobe_PreveriPrekrivanje.
function CheckOverload() {
var ponavljajociDogodek = $('input[id$="RecurrenceField"]').prop('checked');
if (ponavljajociDogodek) {
var context = new SP.ClientContext.get_current();
var web = context.get_web();
context.load(web);
context.executeQueryAsync(function () {
var _zacDatum = moment(new Date(0001, 0, 1, 0, 0, 0, 0));
var _konDatum = moment(new Date(0001, 0, 1, 0, 0, 0, 0));
var _dateHoursInputs = $('select[id$="DateTimeFieldDateHours"]');
if (_dateHoursInputs.length >= 2) {
var _zacUra = parseInt(_dateHoursInputs.eq(0).val());
if (_dateHoursInputs.eq(0).val().indexOf("PM") >= 0) {
_zacUra += 12;
}
_zacDatum = _zacDatum.add(_zacUra, 'hours');
var _konUra = parseInt(_dateHoursInputs.eq(1).val());
if (_dateHoursInputs.eq(1).val().indexOf("PM") >= 0) {
_konUra += 12;
}
_konDatum = _konDatum.add(_konUra, 'hours');
}
else {
_zacDatum = _zacDatum.add(0, 'hours');
_konDatum = _konDatum.add(24, 'hours');
}
var _dateMinutesInputs = $('select[id$="DateTimeFieldDateMinutes"]');
if (_dateMinutesInputs.length >= 2) {
var _zacMinuta = parseInt(_dateMinutesInputs.eq(0).val());
_zacDatum = _zacDatum.add(_zacMinuta, 'minutes');
var _konMinuta = parseInt(_dateMinutesInputs.eq(1).val());
_konDatum = _konDatum.add(_konMinuta, 'minutes');
}
var _datumOd = moment($('input[id$="windowStart_windowStartDate"]').val(), 'D.M.YYYY');
var _datumDo = moment($('input[id$="windowEnd_windowEndDate"]').val(), 'D.M.YYYY');
$.ajax({
url: "/_vti_bin/{web-service-path}/{web-service-name}.svc/SejneSobe_PreveriPrekrivanjePonavljajoce",
data: JSON.stringify({
siteUrl: web.get_url(),
listGuid: _spPageContextInfo.pageListId,
uraOd: _zacDatum.format("HH:mm"),
uraDo: _konDatum.format("HH:mm"),
tipPonovitve: $('input[name$="RecurrencePatternType"]:checked').val(),
dnevnoTipVzorec: $('input[name$="DailyRecurType"]:checked').val(),
dnevnoVsakihDni: $('input[id$="daily_dayFrequency"]').val(),
tedenskoVsakihTednov: $('input[id$="weekly_weekFrequency"]').val(),
dnevi: $('input[name$="weekly_multiDays$0"]:checked').length + "," +
$('input[name$="weekly_multiDays$1"]:checked').length + "," +
$('input[name$="weekly_multiDays$2"]:checked').length + "," +
$('input[name$="weekly_multiDays$3"]:checked').length + "," +
$('input[name$="weekly_multiDays$4"]:checked').length + "," +
$('input[name$="weekly_multiDays$5"]:checked').length + "," +
$('input[name$="weekly_multiDays$6"]:checked').length,
mesecnoTipVzorec: $('input[name$="MonthlyRecurType"]:checked').val(),
mesecnoDan: $('input[id$="monthly_day"]').val(),
mesecnoVsakihMesecev: $('input[id$="monthly_monthFrequency"]').val(),
mesecnoKateri: $('select[id$="monthlyByDay_weekOfMonth"]').val(),
mesecnoDan2: $('select[id$="monthlyByDay_day"]').val(),
mesecnoVsakihMesecev2: $('input[id$="monthlyByDay_monthFrequency"]').val(),
letnoTipVzorec: $('input[name$="YearlyRecurType"]:checked').val(),
letnoVsakMesec: $('select[id$="yearly_month"]').val(),
letnoDan: $('input[id$="yearly_day"]').val(),
letnoKateri: $('select[id$="yearlyByDay_weekOfMonth"]').val(),
letnoDan2: $('select[id$="yearlyByDay_day"]').val(),
letnoVMesecu: $('select[id$="yearlyByDay_month"]').val(),
datumOd: _datumOd.format("DD.MM.YYYY"),
tipDatumDo: $('input[name$="EndDateRangeType"]:checked').val(),
datumDo: _datumDo.format("DD.MM.YYYY"),
stPonovitev: $('input[id$="repeatInstances"]').val()
}),
type: "POST",
cache: false,
dataType: 'json',
contentType: "application/json; charset=utf-8"
})
.done(function (data) {
if (data.ErrorMessage) {
alert(data.ErrorMessage);
}
else {
console.log(data.Data);
if (!data.Data) {
originalSaveButtonClickHandler();
} else {
// izpiši napake
ssIzpisiNapakoCas("Končni čas", "End Time");
}
}
});
});
}
else {
var _zacDatum;
var _konDatum;
$('span#sIzpisiNapakoCas').hide();
var _dateInputs = $('input[id$="DateTimeFieldDate"]');
if (_dateInputs.length >= 2) {
_zacDatum = moment(_dateInputs.eq(0).val(), 'D.M.YYYY');
_konDatum = moment(_dateInputs.eq(1).val(), 'D.M.YYYY');
}
else {
originalSaveButtonClickHandler();
return;
}
var _dateHoursInputs = $('select[id$="DateTimeFieldDateHours"]');
if (_dateHoursInputs.length >= 2) {
var _zacUra = parseInt(_dateHoursInputs.eq(0).val());
if (_dateHoursInputs.eq(0).val().indexOf("PM") >= 0) {
_zacUra += 12;
}
_zacDatum = _zacDatum.add(_zacUra, 'hours');
var _konUra = parseInt(_dateHoursInputs.eq(1).val());
if (_dateHoursInputs.eq(1).val().indexOf("PM") >= 0) {
_konUra += 12;
}
_konDatum = _konDatum.add(_konUra, 'hours');
}
else {
_zacDatum = _zacDatum.add(0, 'hours');
_konDatum = _konDatum.add(24, 'hours');
}
var _dateMinutesInputs = $('select[id$="DateTimeFieldDateMinutes"]');
if (_dateMinutesInputs.length >= 2) {
var _zacMinuta = parseInt(_dateMinutesInputs.eq(0).val());
_zacDatum = _zacDatum.add(_zacMinuta, 'minutes');
var _konMinuta = parseInt(_dateMinutesInputs.eq(1).val());
_konDatum = _konDatum.add(_konMinuta, 'minutes');
}
var context = new SP.ClientContext.get_current();
var web = context.get_web();
context.load(web);
context.executeQueryAsync(function () {
$.ajax({
url: "/_vti_bin/{web-service-path}/{web-service-name}.svc/SejneSobe_PreveriPrekrivanje",
data: JSON.stringify({
SiteUrl: web.get_url(),
ListGuid: _spPageContextInfo.pageListId,
DatumOd: _zacDatum.format("DD.MM.YYYY HH:mm:ss"),
DatumDo: _konDatum.format("DD.MM.YYYY HH:mm:ss")
}),
type: "POST",
cache: false,
dataType: 'json',
contentType: "application/json; charset=utf-8"
})
.done(function (data) {
if (data.ErrorMessage) {
alert(data.ErrorMessage);
}
else {
console.log(data.Data);
if (!data.Data) {
originalSaveButtonClickHandler();
} else {
// izpiši napake
ssIzpisiNapakoCas("Končni čas", "End Time");
}
}
});
});
}
}
If we have conflict with other events in SharePoint Calendar we show simple message to user. If not we call originalSaveButtonClickHandler which take care for OOTB saving of our new event to SharePoint Calendar.

Cheers!
Gašper Rupnik
{End.}

Leave a comment