How to limit the appointment per slot in ASP.Net Core Scheduler ?
This knowledge base article explains the way to prevent the rendering of more appointments in same range.
Step 1: Create a Core sample with by referring the following user guide sample link.
https://help.syncfusion.com/aspnet-core/schedule/getting-started
Also define the Scheduler with before-appointment-create, before-appointment-change, drag-stop and resize-stop client-side events as shown in the following code example.
<ej-schedule id="Schedule1" width="100%" height="525px" current-date="new DateTime(2016, 6, 2)" before-appointment-create="limitAppCount" before-appointment-change="limitAppCount" drag-stop="limitAppCount" resize-stop="limitAppCount"> <e-appointment-settings apply-time-offset="false" id="Id" subject='"Subject"' start-time='"StartTime"' end-time='"EndTime"' all-day='"AllDay"' recurrence='"Recurrence"' recurrence-rule='"RecurrenceRule"'> <e-datamanager id="Data" json="(IEnumerable<SyncfusionASPNETCoreApplication3.Controllers.HomeController.ScheduleData>)ViewBag.datasource"></e-datamanager> </e-appointment-settings> </ej-schedule>
Step 2: When any CRUD action is performed on an appointment, Scheduler events will raise where we can access the updated collection details which is passed to the overlap client-side function to check any other appointment availability on rendering range as shown in the following code example.
function limitAppCount(args) {
if (args.type != 'beforeAppointmentRemove') {
if (ej.isNullOrUndefined(args.appointment[0]))
app = args.appointment;
else
app = args.appointment[0];
if (args.type == 'beforeAppointmentCreate' && args.appointment.length > 0) {
var count = 0;
for (var i = 0; i < args.appointment.length; i++) {
app = args.appointment[i];
count += overlap(app, args.type);
}
}
else if (args.type == "beforeAppointmentChange") {
var count = 0;
if (args.appointment.added.length > 0) {
for (var i = 0; i < args.appointment.added.length; i++) {
app = args.appointment.added[i];
count += overlap(app, args.type);
}
}
app = args.appointment.changed[0];
count += overlap(app, args.type);
} else {
var count = overlap(app, args.type);
}
if (args.type != "resizeStop" && args.type != "dragStop") {
args.cancel = (count > 0);
} else {
args.cancel = (count > 1);
}
}
}
Step 3: In overlap function, the presence of existing appointment within the new appointment’s rendering range will be calculated with in filterAppointment and recOverlap functions for non-recurrence and recurrence appointments respectively as shown in the following code example.
function overlap(app, type) {
var obj = $("#Schedule1").ejSchedule('instance');
var filterApp;
var filApp = [];
var startDate = app[obj._appointmentSettings["startTime"]];
var endDate = app[obj._appointmentSettings["endTime"]];
var resourceId = app["OwnerId"];
if (ej.isNullOrUndefined(app[obj._appointmentSettings["recurrenceRule"]])) {
filterApp = filterAppointment(startDate, endDate);
}
else {
filterApp = recOverlap(app);
}
if ((type == "beforeAppointmentChange")) {
for (var i = 0; i < filterApp.length; i++) {
if (filterApp[i].AppTaskId != app.AppTaskId) {
filApp.push(filterApp[i]);
}
}
filterApp = [];
for (var i = 0; i < filApp.length; i++) {
filterApp.push(filApp[i]);
}
}
var overlapCount = 0;
if (obj._tempResource.length > 0) {
overlapCount = (type == "beforeAppointmentChange" && filterResApp.length == 1 && filterResApp[0].Id == app.Id) ? 0 : filterResApp.length;
}
else {
overlapCount = filterApp.length;
}
return overlapCount;
}
Step 4: In filterAppointment function, start and end time is used to find the overlapping appointment as shown in the following code example.
function filterAppointment(startDate, endDate) {
var obj = $("#Schedule1").ejSchedule('instance');
var predicate = ej.Predicate(obj._appointmentSettings["startTime"], ej.FilterOperators.greaterThanOrEqual, startDate).
and(ej.Predicate(obj._appointmentSettings["endTime"], ej.FilterOperators.greaterThanOrEqual, startDate)).
and(ej.Predicate(obj._appointmentSettings["startTime"], ej.FilterOperators.lessThan, endDate)).
or(ej.Predicate(obj._appointmentSettings["startTime"], ej.FilterOperators.lessThanOrEqual, startDate).
and(ej.Predicate(obj._appointmentSettings["endTime"], ej.FilterOperators.greaterThan, startDate)));
var filterApp = new ej.DataManager(obj._processed).executeLocal(new ej.Query().where(predicate));
return filterApp;
}
Step 5: In recOverlap function, appointment occurrence objects are formed manually based on its rule. With those occurrence objects, overlapping appointment is found as shown in the following code example.
function recOverlap(app) {
var appointment = app;
var obj = $("#Schedule1").ejSchedule('instance');
var recurEdit = obj._recurrenceEditor.ejRecurrenceEditor('instance');
recurEdit._rRule = {};
recurEdit.model.startDate = new Date(obj.currentDate());
var rule = app[obj._appointmentSettings["recurrenceRule"]];
var collection = recurEdit.recurrenceDateGenerator(appointment[obj._appointmentSettings["recurrenceRule"]], appointment[obj._appointmentSettings["startTime"]], appointment[obj._appointmentSettings["recurrenceExDate"]]);
var newArray = collection;
var filter = [];
var i = 0;
while (i < newArray.length) {
var orgStrTime = new Date(newArray[i]), orgEndTime = appointment[obj._appointmentSettings["endTime"]];
((recurEdit._rRule.freq == "MONTHLY" || recurEdit._rRule.freq == "YEARLY") && !ej.isNullOrUndefined(recurEdit._rRule.setPositions)) && (orgStrTime = recurEdit._dayOfWeekInMonth(orgStrTime, recurEdit._rRule.weekDays, recurEdit._rRule.setPositions));
var strTime = new Date(orgStrTime.getFullYear(), orgStrTime.getMonth(), orgStrTime.getDate(), new Date(appointment[obj._appointmentSettings["startTime"]]).getHours(), new Date(appointment[obj._appointmentSettings["startTime"]]).getMinutes(), new Date(appointment[obj._appointmentSettings["startTime"]]).getSeconds());
var endTime = new Date(new Date(strTime).setMilliseconds(appointment[obj._appointmentSettings["endTime"]].getTime() - appointment[obj._appointmentSettings["startTime"]].getTime()));
var fil = filterAppointment(strTime, endTime);
if (typeof fil !== 'undefined' && fil.length > 0) {
for (var j = 0; j < fil.length; j++) {
filter.push(fil[j]);
// To add exclude date
app[obj._appointmentSettings["recurrenceRule"]] = ej.isNullOrUndefined(app[obj._appointmentSettings["recurrenceExDate"]]) ? rule + ";EXDATE=" + ej.format(strTime, obj._pattern.d, obj.model.locale) : app[obj._appointmentSettings["recurrenceRule"]] + "," + ej.format(strTime, obj._pattern.d, obj.model.locale);
app[obj._appointmentSettings["recurrenceExDate"]] = !ej.isNullOrUndefined(app[obj._appointmentSettings["recurrenceExDate"]]) ? app[obj._appointmentSettings["recurrenceExDate"]] + "," + ej.format(strTime, obj._pattern.d, obj.model.locale).toString() : ej.format(strTime, obj._pattern.d, obj.model.locale).toString();
}
}
i++;
}
return filter;
}
Step 6: Run the sample and no two appointments can be rendered in the same time range as shown below.

Figure 1: Adding second appointment in another appointment range.

Figure 2: Second appointment is not rendered, due to the presence of another appointment in same range.
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/Sample727027404