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