I have a kendo scheduler with day, week and month views. when user selects the cell it there is widget to click with startdate and enddate.
This works fine for day and week, except month.
When selecting the month it gives the "Uncaught TypeError: Cannot read properties of undefined (reading 'value')".
Kendo scheduler :
View.scheduler = $(this.schedulerElementWithHash).kendoScheduler({
allDaySlot: false,
date: Model.startDate,
startTime: Model.startTime,
endTime: Model.endTime,
workDayStart: Model.workDayStart,
workDayEnd: Model.workDayEnd,
majorTimeHeaderTemplate: kendo.template("<strong>#=kendo.toString(date, 'H:mm')#</strong>"),
snap: false,
majorTick: 60,
selectable: true,
editable: {
destroy: true
},
messages: {
deleteWindowTitle: "Delete",
destroy: "UnSchedule"
},
navigate: function (e) {
//if (e.action == 'previous' || e.action == 'next') {
// // added some delay to make sure that the view start/end date has been updated prior to reading
// setTimeout(function () {
// View.scheduler.dataSource.read();
// }, 100);
//}
if (e.action == 'previous' || e.action == 'next') {
View.scheduler.dataSource.options.serverFiltering = true;
}
View.schedulerNavigated = e.action == 'changeWorkDay';
if (e.action == 'changeView') {
View.setCalendarWidth(e.view);
}
},
height: 800,
eventTemplate: $("#visit-schedule-template").html(),
views: [
{ type: "day", selected: SchedulerView.isDaySelected, dateHeaderTemplate: "<span class='k-link k-nav-day'>#=kendo.toString(date, 'ddd dd-MMM')#</span>" },
{ type: "week", selected: SchedulerView.isWeekSelected, showWorkHours: true, dateHeaderTemplate: "<span class='k-link k-nav-day'>#=kendo.toString(date, 'ddd dd-MMM')#</span>" },
{ type: "month", selected: SchedulerView.isMonthSelected, showWorkHours: false }
],
groupHeaderTemplate: $("#groupHeaderTemplate").html(),
//timezone: "Etc/UTC",
dataSource: {
//filter: {
// logic: 'or'
//},
batch: true,
serverFiltering: true,
transport: {
read: function (options) {
if (View.schedulerNavigated) {
console.log("read schedulerNavigated = true");
options.success(View.scheduler.dataSource.data());
return;
}
var scheduler = $(View.schedulerElementWithHash).data("kendoScheduler");
var view = scheduler.view();
var startDate = moment(view.startDate()).startOf('day').utc().format();
var endDate = moment(view.endDate()).endOf('day').utc().format();
Controller.visitService.getScheduleCalenderEntries(startDate, endDate).done(function (response) {
options.success(response);
})
},
update: function (options) {
$.ajax({
url: "/iapis/visits/update",
data: kendo.stringify(options.data.models),
type: "POST",
contentType: 'application/json',
success: function (response) {
var resp = response.Data.map(d => d.map(v => ({
id: v.Id,
crewId: v.crewId,
end: v.end,
start: v.start,
title: v.title
})));
options.success(resp);
}
});
},
create: function (options) {
options.success(null);
},
destroy: function (options) {
options.success(null);
},
parameterMap: function (options, operation) {
console.log('options', options);
if (operation !== "read" && options.models) {
return kendo.stringify(options.models);
}
//return {
// filter: ['ScheduledDate~isnotnull~undefined~and~CrewId~eq~13']
//};
}
},
schema: {
//timezone: "Etc/UTC",
parse: function (response) {
console.log('parse response', response);
if (View.schedulerNavigated) {
console.log("parse schedulerNavigated = true");
View.schedulerNavigated = false;
return response;
}
// store transformed user data
var visitsData = [];
if (response.length > 0) {
for (var i = 0; i < response.length; i++) {
var item = response[i];
// Only add if there is Start and End Date
if (item.start && item.end) {
var lastVisitStr = View.getLastVisitConverted(item.lastVisited);
var slot = {
id: item.id,
title: item.type == 'visit' ? item.apairy : 'Break',
start: item.start,
//startTimezone: 'Etc/UTC',
end: item.end,
//endTimezone: 'Etc/UTC',
completed: item.completed,
calculatedDuration: item.calculatedDuration,
crewId: item.crewId,
crew: item.crew,
type: item.type,
apiary: item.apairy,
apiaryId: item.apiaryId,
//lastVisited: item.LastVisited,
lastVisited: lastVisitStr,
ago: View.calcDaysAgo(lastVisitStr), // a day
status: item.status,
taskCount: item.tasksCount.toLocaleString(),
latitude: item.latitude,
longitude: item.longitude,
apiaryOffroadTime: item.apiaryOffroadTime,
apiaryOffroadDistance: item.apiaryOffroadDistance,
color: item.color,
crewColor: item.crewColor ? item.crewColor : Model.defaultCrewColor,
distance: item.distance,
durationMinutes: item.durationMinutes,
onroadTime: item.onroadTime,
onroadDistance: item.onroadDistance,
offroadTime: item.offroadTime,
offroadDistance: item.offroadDistance,
visitFirst: item.visitFirst,
visitFirstLat: item.visitFirstLatitude,
visitFirstLong: item.visitFirstLongitude,
visitLast: item.visitLast,
visitLastLat: item.visitLastLatitude,
visitLastLong: item.visitLastLongitude,
visitStatus: item.visitStatus,
previousVisitId: item.previousVisitId,
nextVisitId: item.nextVisitId,
fromVisitId: item.fromVisitId,
toVisitId: item.toVisitId,
};
if (item.type == 'visit' && item.groupIds) {
slot.groupIds = item.groupIds.split(',');
slot.groupIds = _.map(slot.groupIds, function (e) {
try {
return parseInt(e)
} catch (err) {
//do nothing
console.log('error parsing group id');
}
});
}
if (item.type == 'break') {
slot.defaultBreakSlotColor = Model.defaultBreakSlotColor
}
visitsData.push(slot);
}
else {
// Read all items modified and set Dirty = True
var dirtySlots = [];
for (var j = 0; j < item.length; j++) {
//var slotModified = item[item.length - 1];
slotModified = item[j];
var slot = _.find(View.scheduler.dataSource.data(), function (e) {
return e.id == slotModified.id;
});
if (slot) {
dirtySlots.push(slot);
}
if (slotModified.id == 0) {
slotModified.end = new Date(slotModified.end);
slotModified.start = new Date(slotModified.start);
if (slotModified.end.getMinutes() > 30) {
slotModified.end.setMinutes(30);
}
if (slotModified.end.getMinutes() < 30) {
slotModified.end.setMinutes(0);
}
if (slotModified.start.getMinutes() < 30) {
slotModified.start.setMinutes(0);
}
if (slotModified.start.getMinutes() > 30) {
slotModified.start.setMinutes(30);
}
}
visitsData.push({
id: slotModified.id,
title: slotModified.title,
start: slotModified.start,
end: slotModified.end,
crewId: slotModified.crewId,
dirty: true
});
}
setTimeout(function () {
dirtySlots.forEach(function (slot) {
slot.dirty = true;
});
}, 500);
}
} //end for loop, done adding items to array
//update resources the first time
if (Model.crewsInVisit && Model.crewsInVisit.length == 0) {
View.scheduler.dataSource.options.serverFiltering = false;
Model.crewsInVisit = Controller.getCrewsFromVisit(visitsData);
console.log('grouped crews', Model.crewsInVisit);
var crewRecords = _.chain(Model.crewsInVisit)
.filter(function (item) {
return item.value !== 'null';
});
Model.crewsInVisit = crewRecords._wrapped;
//update Crew multiselect
View.bindCrewMultiSelect();
View.renderRegionsMultiselect();
Controller.refreshResources();
}
$(".k-loading-image").hide();
$(".k-loading-mask").hide();
View.scheduler.refresh();
return visitsData;
}
else {
console.log('Model.allCrews', Model.allCrews);
if (Model.allCrews.length === 0 || Model.allCrews.length < 0) {
abp.message.info('', 'Please add at least one crew to iAPIS settings!!');
}
return visitsData;
}
}
}
},
group: {
resources: ["Crew"]
},
resources: [
{
field: "crewId",
name: "Crew",
dataSource: Model.crewsInVisit,
//dataColorField: 'none',
title: "Crew",
multiple: false,
}
],
dataBound: function (e) {
console.log('data bound');
$('k-loading-mask').hide();
Controller.colorVisitAccordingToStates();
var scroll_l = 0, scroll_t = 0;
var tenantId = abp.session.tenantId;
var ScrollX = "ScrollX";
var ScrollY = "ScrollY";
if (this.viewName()) {
var strDate = $(".k-lg-date-format").html();
if (strDate.indexOf(',') > 0) {
var strSplit = strDate.split('-');
var dateFormat = 'ddd dd-MMM-yyyy';
if (this.viewName() === "month") {
dateFormat = 'MMM-yyyy'
}
var dateConverted = kendo.toString(kendo.parseDate(strSplit[0].trim()), dateFormat);
if (strSplit.length == 2) {
dateConverted += " - " + kendo.toString(kendo.parseDate(strSplit[1].trim()), dateFormat);
}
$(".k-lg-date-format").html(dateConverted);
$(".k-sm-date-format").html(dateConverted);
}
}
if (localStorage.getItem(ScrollX.concat(tenantId)) && localStorage.getItem(ScrollY.concat(tenantId))) {
scroll_l = localStorage.getItem(ScrollX.concat(tenantId));
scroll_t = localStorage.getItem(ScrollY.concat(tenantId));
$('#schedulers .k-scheduler-content').scrollLeft(scroll_l);
$('#schedulers .k-scheduler-content').scrollTop(scroll_t);
}
$('.k-scheduler-content').scroll(function () {
if ($('#schedulers .k-scheduler-content').html().length) {
scroll_l = $('#schedulers .k-scheduler-content').scrollLeft();
scroll_t = $('#schedulers .k-scheduler-content').scrollTop();
localStorage.setItem(ScrollX + tenantId, scroll_l.toString());
localStorage.setItem(ScrollY + tenantId, scroll_t.toString());
}
});
if (app.utils.iapis.getUrlParameters) {
var visitId = app.utils.iapis.getUrlParameters('visitId');
if (visitId) {
var uid = $('div[visit-Id=' + visitId + ']').parent().attr('data-uid');
if (uid) {
var contentDiv = View.scheduler.element.find("div.k-scheduler-content");
var contentDivPosition = contentDiv.position();
var eventDiv = $(".k-event[data-uid=" + uid + "]");
var eventDivOffset = eventDiv.offset();
contentDiv.scrollLeft(eventDivOffset.left + contentDiv.scrollLeft() - contentDivPosition.left*2.25);
contentDiv.scrollTop(eventDivOffset.top + contentDiv.scrollTop() - contentDivPosition.top);
}
}
}
setTimeout(function () {
View.scheduler.view().table.on("mousedown", function (e) {
if (e.which === 3) {
var slot = View.scheduler.slotByElement($(e.target));
View.scheduler.select({ start: slot.startDate, end: slot.endDate });
}
});
}, 1);
// Create Date Header Tooltip
var mouseX = 0;
var mouseY = 0;
var onMouseUpdateDateTooltip = function (e) {
mouseX = e.screenX;
mouseY = e.screenY;
};
document.addEventListener('mousemove', onMouseUpdateDateTooltip, false);
console.log('creating tooltip');
$(".k-scheduler-date-group").kendoTooltip({
filter: "span",
width: 250,
content: function (e) {
var date = e.target.html();
var calendarDate = moment(View.scheduler.view().startDate());
var referenceDate = moment.utc(date + '-' + calendarDate.format('YYYY'));
var crewGroupCells = $('.k-scheduler-group-cell');
var dateIndex = e.target.parent().index();
var selectedView = View.scheduler.view().title.toLowerCase();
var crew = null;
if (selectedView == 'week') {
dateIndex = Math.floor(dateIndex / 7);
}
if (dateIndex >= 0) {
var hoveredGroup = $(crewGroupCells[dateIndex]).find('.crew-group');
var crewId = hoveredGroup.attr('id').replace('C', '');
crew = Model.allCrews.find(x => x.value == crewId);
}
if (crew && referenceDate.isValid()) {
var tooltipContent = $('.k-tooltip-content');
var tooltipInCache = View.tooltipCache[crew.value + '_' + referenceDate.format('DD-MMM-YYYY')];
if (tooltipInCache) {
return tooltipInCache;
}
else
{
Controller.visitService.getVisitCrewData(referenceDate, crew.value)
.done(function (response) {
if (response.length == 1) {
var crew = response[0];
var tooltip = "<h5>" + crew.crewName + "</h5>" +
"<p><b>Vehicle: </b>" + (crew.vehicle == null ? 'None' : crew.vehicle) +
"<p><b>Workers: </b>";
if (crew.crewMembersList && crew.crewMembersList.length > 0) {
tooltip += "<ul>";
_.forEach(crew.crewMembersList, function (worker) {
tooltip += "<li>" + worker.workerName + " (" + worker.workerMPE + "%)";
_.forEach(worker.tasksMPE, function (workerTask) {
tooltip += "<br> - " + workerTask.taskName + " (" + workerTask.taskMPE + "%)";
});
tooltip += "</li>";
});
tooltip += "</ul>";
}
else {
tooltip += "None";
}
tooltipContent.html(tooltip);
View.tooltipCache[crew.crewId + '_' + referenceDate.format('DD-MMM-YYYY')] = tooltip;
}
else {
tooltipContent.html('Error Loading!');
}
})
.catch(function (err) {
tooltipContent.html('Error Loading!');
console.error('Error Loading Tooltip: ' + err);
});
return 'Loading...';
}
}
else {
return 'Error Loading!';
}
},
show: function () {
this.refresh();
}
});
View.setScheduleDropArea(this);
},
})
.data("kendoScheduler");
Cell select event :
setTimeout(function () {
View.scheduler.view().table.on("mousedown", function (e) {
if (e.which === 3) {
var slot = View.scheduler.slotByElement($(e.target));
View.scheduler.select({ start: slot.startDate, end: slot.endDate });
}
});
}, 1);
The data is correct when selecting the cell but "
View.scheduler.select({ start: slot.startDate, end: slot.endDate });
"
gives the
kendo.all.js:313050 Uncaught TypeError: Cannot read properties of undefined (reading 'value')
at init._setResourceValue (kendo.all.js:313050:21)
at init._resourceBySlot (kendo.all.js:313050:21)
at init._select (kendo.all.js:313050:21)
at init.select (kendo.all.js:313050:21)
at HTMLTableElement.<anonymous> (schedule.js?v=tx40wPU-Cw8se20BEdtsj55bdCvwHSPJLBm64UIbYaQ:2214:48)
at HTMLTableElement.dispatch (app-layout-libs.min.js?v=5e4tlbUYEHnHcS5q_Z-XKjK0gw8I56pGLzYM0eJF0IE:5977:27)
at elemData.handle (app-layout-libs.min.js?v=5e4tlbUYEHnHcS5q_Z-XKjK0gw8I56pGLzYM0eJF0IE:5781:28)
Any idea about what could be the issue?
Some users do not see very clearly which is the today in the scheduler and asked if the header could be colored.
I have found that the cells has the class "k-today" but the header does not have it.
Is there a way to know which of the header cells is the cell for the today?
I want to trigger an event add when a user highlights a time range on a scheduler.
I can pick up when the user lets go of the mouse on the calendar using
scheduler.wrapper.on("mouseup touchend", ".k-scheduler-table td, .k-event", function (e) {
});
but i can't figure out how to get the selected slot range from there.
seem to be able to get the end time of the selected range via the slotbyelement(e.target), but i can't figure out how to get the start time.
Hello,
I'm trying to implement a tooltip that shows how many and what kind of events the resource has for the day when hovering mouse cursor over resource. I was able to do this in day/week/month views by using a custom group header template but I'm having a hard time trying to implement it in agenda view because I'm not able to make a custom template for resource group header, only event date, event time and event custom templates are available as far as I'm aware. Basically what I need is the ability, when hovering over a resource, to know what resource and what date it is to get the relevant information.
Any help is greatly appreciated! Thank you!
Hi, perhaps this is intended functionality for reasons I'm not understanding, but when navigating within a Kendo Scheduler that has certain view types set (particularly, "week" for my purpose), the date that's received in the "navigate" event handler is inconsistent depending on which direction navigation is performed.
When navigating forward, the e.date value is that of the first day of the currently displayed week, as I would expect. However, when navigating backward, the e.date value is the last day of the displayed week. Is there a reason that the day of week for the event date is not the same regardless of which direction navigation is performed?
The console output of this Dojo exhibits the date discrepancy: https://dojo.telerik.com/eMEtuhAQ/2
Thanks!
We have a page which loads a Scheduler, and we pass various information to define what data is loaded in. That all works fine, and we can click PDF Export and it exports absolutely as we'd expect.
We make fairly heavy use of the templates, so we could end up with something that looks like this:
There are about 200 different schedules that we might show depending on the data, and what we'd like to do is be able to automate the export.
We could write a script that loads the page and simulates a button click, however, if there is some better way, I'd MUCH rather do that so we're not dependent on waiting for the page to display on some computer somewhere.
I can pass the parameters needed in the URL - but not sure if there is some way on the page I can automate that PDF Export without first displaying the scheduler page.
Any help would be greatly appreciated!
Thanks
Hi Guys,
I have just noticed an issue with the Scheduler component whereby the dataBound event is constantly being fired during resize events.
To illustrate the problem run the following dojo
https://dojo.telerik.com/uCaQOcEX
and then resize the browser window and you will see multiple 'dataBound' messages hitting the console.log
Running a similar test with the Grid component for comparison
https://dojo.telerik.com/ifoHEDUd
does not cause these multiple dataBound events on resize.
Therefore I suspect this is not the expect behaviour of the Scheduler component but a bug within the code.
Please advise.
Regards
Alan
Hi,
What I am trying to achieve:
Have a local array of my objects to be displayed by the scheduler, then I would need to remove some of them, and at the same time insert new ones
When the page first loads, it works ok, as soon as I try to update the underline data source I get the error:
TypeError: Cannot read properties of null (reading 'getTimezoneOffset')
To reproduce, please press the "Update" button. (I have attached a sample) PS: Please note that I am currently using: kendo.2022.1.412 ( I forgot to update the sample, but it throws the same error)
And one more question, for the scheduler then to reflect the changes , do I need to call the scheduler.view? or will it be ok to just trigger the scheduler.dataSource.read()?
//update scheduler
var scheduler = $("#scheduler").data("kendoScheduler");
scheduler.dataSource.read();
//scheduler.view(scheduler.view().name) ----> do we really need this?
Thanks,