1

I am currently creating a calendar that will display repeating classes for a student for a university project. I am able to display the repeating events on the calendar, but whenever I attempt to resize or drag and drop an event I am getting the following errors in the browser web console:

TypeError: this.eventInstances[0] is undefined [Learn More] fullcalendar.min.js:6:26715

TypeError: t is undefined [Learn More] fullcalendar.min.js:8:6813

This is the JSON being passed into the calendar:

[{"id":22,"title":"Class: CSC3047\n Location: DKB","start":"12:00","end":"14:00",
"allDay":false,"description":"Mr Jack Dell","dow":[1],"ranges":[{"start":"2018-03-12",
"end":"2018-10-15"}]},{"id":23,"title":"Class: CSC3056\n Location: Ashby","start":"09:00",
"end":"11:00","allDay":false,"description":"Narelle Allen","dow":[3],
"ranges":[{"start":"2018-03-12","end":"2018-10-15"}]}]

This is the javascript I am using to display/edit/update the calendar events:

var currentUpdateEvent;
var addStartDate;
var addEndDate;
var globalAllDay;

function updateEvent(event, element) {
    //alert(event.description);

    if ($(this).data("qtip")) $(this).qtip("destroy");

    currentUpdateEvent = event;

    $('#updatedialog').dialog('open');

    $("#eventName").val(event.title);
    $("#eventDesc").val(event.description);
    $("#eventId").val(event.id);
    $("#eventStart").text("" + event.start.toLocaleString());

    if (event.end === null) {
        $("#eventEnd").text("");
    }
    else {
        $("#eventEnd").text("" + event.end.toLocaleString());
    }

}

function updateSuccess(updateResult) {
    //alert(updateResult);
}

function deleteSuccess(deleteResult) {
    //alert(deleteResult);
}

function addSuccess(addResult) {
    // if addresult is -1, means event was not added
    //    alert("added key: " + addResult);

    if (addResult != -1) {
        $('#calendar').fullCalendar('renderEvent',
            {
                title: $("#addEventName").val(),
                start: addStartDate,
                end: addEndDate,
                id: addResult,
                description: $("#addEventDesc").val(),
                allDay: globalAllDay
            },
            true // make the event "stick"
        );


        $('#calendar').fullCalendar('unselect');
    }

}

function UpdateTimeSuccess(updateResult) {
    //alert(updateResult);
}


function selectDate(start, end, allDay) {

    $('#addDialog').dialog('open');


    $("#addEventStartDate").text("" + start.toLocaleString());
    $("#addEventEndDate").text("" + end.toLocaleString());


    addStartDate = start;
    addEndDate = end;
    globalAllDay = allDay;
    //alert(allDay);

}

function updateEventOnDropResize(event, allDay) {

    //alert("allday: " + allDay);
    var eventToUpdate = {
        id: event.id,
        start: event.start

    };

    if (allDay) {
        eventToUpdate.start.setHours(0, 0, 0);

    }

    if (event.end === null) {
        eventToUpdate.end = eventToUpdate.start;

    }
    else {
        eventToUpdate.end = event.end;
        if (allDay) {
            eventToUpdate.end.setHours(0, 0, 0);
        }
    }

    eventToUpdate.start = eventToUpdate.start.format("DD-MM-YYYY hh:mm A");
    eventToUpdate.end = eventToUpdate.end.format("DD-MM-YYYY hh:mm A");

    PageMethods.UpdateEventTime(eventToUpdate, UpdateTimeSuccess);
    $('#calendar').fullCalendar('refetchEvents');

}

function eventDropped(event, dayDelta, minuteDelta, revertFunc) {

    updateEventOnDropResize(event);



}

function eventResized(event, dayDelta, minuteDelta, revertFuncc) {

    updateEventOnDropResize(event);

}

function checkForSpecialChars(stringToCheck) {
    var pattern = /[^A-Za-z0-9 ]/;
    return pattern.test(stringToCheck);
}


$(document).ready(function () {

    // update Dialog
    $('#updatedialog').dialog({
        autoOpen: false,
        modal: true,
        width: 470,
        buttons: {
            "update": function () {
                //alert(currentUpdateEvent.title);
                var eventToUpdate = {
                    id: currentUpdateEvent.id,
                    title: $("#eventName").val(),
                    description: $("#eventDesc").val()
                };

                if (checkForSpecialChars(eventToUpdate.title) || checkForSpecialChars(eventToUpdate.description)) {
                    alert("please enter characters: A to Z, a to z, 0 to 9, spaces");
                }
                else {
                    PageMethods.UpdateEvent(eventToUpdate, updateSuccess);
                    $(this).dialog("close");

                    currentUpdateEvent.title = $("#eventName").val();
                    currentUpdateEvent.description = $("#eventDesc").val();
                    $('#calendar').fullCalendar('updateEvent', currentUpdateEvent);
                }

            },
            "delete": function () {

                if (confirm("do you really want to delete this event?")) {

                    PageMethods.deleteEvent($("#eventId").val(), deleteSuccess);
                    $(this).dialog("close");
                    $('#calendar').fullCalendar('removeEvents', $("#eventId").val());
                }

            }

        }
    });

    //add dialog
    $('#addDialog').dialog({
        autoOpen: false,
        width: 470,
        buttons: {
            "Add": function () {

                //alert("sent:" + addStartDate.format("dd-MM-yyyy hh:mm:ss tt") + "==" + addStartDate.toLocaleString());
                var eventToAdd = {
                    title: $("#addEventName").val(),
                    description: $("#addEventDesc").val(),
                    start: addStartDate.format("DD-MM-YYYY hh:mm A"),
                    end: addEndDate.format("DD-MM-YYYY hh:mm A")

                };

                if (checkForSpecialChars(eventToAdd.title) || checkForSpecialChars(eventToAdd.description)) {
                    alert("please enter characters: A to Z, a to z, 0 to 9, spaces");
                }
                else {
                    //alert("sending " + eventToAdd.title);

                    PageMethods.addEvent(eventToAdd, addSuccess);
                    $(this).dialog("close");
                }

            }

        }
    });

    // page is now ready, initialize the calendar...

    var date = new Date();
    var d = date.getDate();
    var m = date.getMonth();
    var y = date.getFullYear();

    var calendar = $('#calendar').fullCalendar({
        // put your options and callbacks here
        header:
        {
            left: 'title',
            center: '',
            right: 'month,agendaDay,agendaWeek, prev,next'
        },
        height: 490,
        //contentHeight: auto,
        titleFormat: 'MMMM D YYYY',
        columnFormat: 'ddd D/M',
        defaultView: 'agendaWeek',
        handleWindowResize: true,
        allDaySlot: true,
        minTime: '09:00:00',
        maxTime: '18:00:00',
        slotLabelFormat: 'h(:mm)a',
        slotLabelInterval: '01:00:00',
        firstDay: 1,
        weekends: false,
        hiddenDays: [6, 7],
        eventClick: updateEvent,
        selectable: true,
        selectHelper: true,
        select: selectDate,
        editable: true,
        eventDrop: eventDropped,
        eventResize: eventResized,
        events: {
            url: 'JsonResponse.ashx',
            color: 'blue',
            error: function () {
                alert('Error while Getting events!');
            }
        },
        eventRender: function (event, element) {
            //alert(event.title);
            element.qtip({
                content: event.description,
                position: { corner: { tooltip: 'bottomLeft', target: 'topRight' } },
                style: {
                    border: {
                        width: 1,
                        radius: 3,
                        color: '#0000ff'

                    },
                    padding: 10,
                    textAlign: 'center',
                    tip: true, // Give it a speech bubble tip with automatic corner detection
                    name: 'cream' // Style it according to the preset 'cream' style
                }

            });
            return (event.ranges.filter(function (range) { // test event against all the ranges

                return (event.start.isBefore(range.end) &&
                    event.end.isAfter(range.start));

            }).length) > 0;
        }


    });

});

I may be wrong, but I have a feeling that the issue is that qtip is not able to tell which event is in focus due to the ranges value being passed in. Another thing to note is that if I attempt to resize the event twice it will update the database with the new values but will not actually resize the event on the calendar and the event will not update on the calendar until I refresh the page.

Stack trace from browser:

TypeError: this.eventInstances[0] is undefined
[Learn More]
fullcalendar.min.js:6:26715
s</t.prototype.getEventDef
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:26715
d</t.prototype.isEventInstanceGroupAllowed
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:9:10438
l</e.prototype.isEventInstanceGroupAllowed
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:7:13696
hitOver
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:10:24171
a</t.prototype.trigger
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:15714
l</e.prototype.handleHitOver
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:28967
l</e.prototype.handleDragStart
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:28573
a</t.prototype.startDrag
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:14363
a</t.prototype.handleDistanceSurpassed
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:15289
a</t.prototype.handleMove
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:14610
a</t.prototype.handleMouseMove
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:15474
d
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:2:3854
e
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:16679
dispatch
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:12392
add/r.handle
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:9156
trigger
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:11571
triggerHandler
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:19064
s</e.prototype.trigger
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:16925
u</t.prototype.handleMouseMove
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:20528
d
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:2:3854
dispatch
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:12392
add/r.handle
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:9156
TypeError: t is undefined
[Learn More]
fullcalendar.min.js:8:6813
o</t.prototype.buildNewDateProfile
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:6813
l</t.prototype.mutateSingle
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:7:6026
f</t.prototype.mutateEventsWithId/<
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:11:28483
forEach self-hosted:271:13 f</t.prototype.mutateEventsWithId
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:11:28434
p</e.prototype.reportEventResize
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:7:22052
interactionEnd
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:10:24614
a</t.prototype.trigger
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:15714
a</t.prototype.handleInteractionEnd
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:13682
l</e.prototype.handleInteractionEnd
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:29260
a</t.prototype.endInteraction
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:8:13574
d
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:2:3854
e
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:16679
dispatch
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:12392
add/r.handle
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:9156
trigger
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:11571
triggerHandler
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:19064
s</e.prototype.trigger
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:16925
u</t.prototype.handleMouseUp
http://kmartin41.public.cs.qub.ac.uk/QSIS/js/fullcalendar.min.js:6:20621
d
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:2:3854
dispatch
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:12392
add/r.handle
https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js:3:9156

I have based my repeating events off the following answer: https://stackoverflow.com/a/29393128/5659955

Thanks in advance!

Community
  • 1
  • 1
  • `if ($(this).data("qtip")) $(this).qtip("destroy");` is repeated in multiple places, usually just before you run "updateEvent", which also runs the same command. Seems a bit redundant. Probably not the source of your problem, but looks like unnecessary code. – ADyson Mar 14 '18 at 13:47
  • And since the errors are coming from the fullCalendar file, it's difficult to see how this could be related to qtip. If you take the qtip bit out, does it go away? I somehow doubt it. Also, what's the stack trace of your code - which exact line in your code is the line which first triggers these errors? Lastly your "runnable" code snippet doesn't run because you haven't included any of the JS references or any accompanying HTML. If you're going to use snippets, make it actually work. If not, just leave it as a regular code block. – ADyson Mar 14 '18 at 13:50
  • @ADyson thanks for your response. You are correct in saying if I removed if ($(this).data("qtip")) $(this).qtip("destroy"); The errors still persist. I am trying to do a stack trace on this however it is hosted on a web server and edited over ftp, so I'm having some difficulty. – Hip Hip Array Mar 14 '18 at 14:27
  • @ADyson from setting some breakpoints in my code I haven't been able to track down what line is triggering these errors. However it seems "this.eventInstances[0] is undefined" is caused on the actual click of the event resize and "TypeError: t is undefined" is caused on the release of the mouse click for resize. I'm at a loss with what is causing this. – Hip Hip Array Mar 14 '18 at 14:53
  • " I am trying to do a stack trace on this however it is hosted on a web server and edited over ftp, so I'm having some difficulty." The stack trace will be shown in your browser's developer tools, no matter where the site is hosted. I don't know which browser you're testing with but Chrome, for one, usually shows this very clearly in the console, especially if you expand the error message. There should be no need for breakpoints. – ADyson Mar 14 '18 at 14:54
  • Stack trace from browser has been added. – Hip Hip Array Mar 14 '18 at 15:28
  • What version of fullCalendar are you using? For a long time fullCalendar has required jQuery 2 or later, but according to that stack trace you're using 1.12. See https://fullcalendar.io/support. You should check that you've got the right version of momentJS as well. This is the most basic stuff you should be checking when you set up your application – ADyson Mar 14 '18 at 15:31
  • Another mistake I've just noticed: `eventToUpdate.start` and `eventToUpdate.end` are momentJS objects. You can't call `setHours()` on them - that's a method on the native JS Date object. If that code ever runs you'll get an error because you're trying to call a function which doesn't exist on the object in question. You need to use momentJS's functions to manipulate the date instead: http://momentjs.com/docs/#/get-set/ . – ADyson Mar 14 '18 at 15:37
  • And calling `$('#calendar').fullCalendar('refetchEvents');` at the end of the resize callback makes no sense. 1) The calendar has _already changed_ the event and resized it by this time. There's no need to refresh it from the server to show that. 2) You're likely calling this before the ajax request to Update the event has finished, so you're likely to get back the old version of the event, which will then replace the recently resized one in the calendar display. This is because ajax requests run asynchronously in the background. The rest of the JS code doesn't wait for them to complete. – ADyson Mar 14 '18 at 15:40
  • P.S. I don't think any of this has to do with the repeating events functionality either. The events created by that method are created on the calendar as individual events and treated as such, regardless of how they're defined on the server. The Javascript code will treat them the same as any other event. Try not to make assumptions about cause and effect, and seek to _demonstrate_ them instead (e.g. if you suspect the repeating events code, then remove it and see what happens, just like we did with the qtip. It's easy to prove that something is _not_ related to a problem.) – ADyson Mar 14 '18 at 15:43
  • @ADyson Thanks for the response. I have looked into all of the points you have mentioned. I have removed the refetch. You where correct in saying I was using an old version of jquery, so I have updated this to v 3.3.1. My version of fullcalendar is v 3.8.2. I have tracked down "this.eventInstances[0] is undefined" to the following code in the fullcalendar js file EventInstanceGroup.prototype.getEventDef = function () { return this.explicitEventDef || this.eventInstances[0].def; }; – Hip Hip Array Mar 14 '18 at 16:14
  • What about momentJS as well? That trace is good but now we need to know what caused the getEventDef function to be executed, and/or what causes (or doesn't cause) the eventInstances array to be populated. This could be a long process. However, unless there really is a bug in fullCalendar, it's more likely that something wrong in your code is causing it to fall over. If we can't trace it directly to a line in your code, then trial and error is probably better - start removing things from the eventresize callback until it resizes happily. That might give us a clue – ADyson Mar 14 '18 at 16:20
  • If it's not that, then start looking at other things that are nonstandard and might be an issue e.g. the event JSON data, and the repeating events stuff. – ADyson Mar 14 '18 at 16:20
  • @ADyson after playing about with this and reverting back to near standard calendar I have found the issue. It seems whenever dow is introduced the resize functionality breaks! – Hip Hip Array Mar 14 '18 at 17:07
  • Actually I wondered about that. In your JSON above, you're setting the value of `dow` as a string, but it should be an array. `"dow":"[3]"` should be `"dow":[3]`, for instance. I suspect fullCalendar is not reading that value correctly. – ADyson Mar 14 '18 at 17:08
  • I've modified it so my JSON matches what you have mentioned. Unfortunately I am still getting the same error. Will update my question with new JSON. – Hip Hip Array Mar 14 '18 at 17:34
  • @ADyson Thanks for all your help. It appears it is a bug that has already been raised: https://github.com/fullcalendar/fullcalendar/issues/3824 It appears fullcalendar cannot handle a start and end without a date. – Hip Hip Array Mar 14 '18 at 18:13
  • The bug makes sense. Without a date in the `start`, how should it behave? I hadn't really thought about it like that. Giving it a bit more consideration actually, dragging/dropping an event which is part of a recurring sequence doesn't fully make sense in itself either, conceptually. You're basically taking the event out of that sequence as it no longer conforms to the recurrence rule. So...what is it in the database which is being updated? Presumably the event in the server is really just one event with a repetition rule? – ADyson Mar 14 '18 at 19:33
  • So in reality you have to 1) create a new event, and 2) update the "source" event to change the repetition rule so that the moved/changed event is no longer generated when the rule is applied. A bit like in Outlook when if you go into a repeated event it asks you if you want to alter the individual event or the whole sequence. – ADyson Mar 14 '18 at 19:34

1 Answers1

1

As mentioned in my comment there was a bug raised against fullcalendar for resizing events that only have a time for their start and end. github.com/fullcalendar/fullcalendar/issues/3824

To get around this I have taken the calendar start and end range and created a list of all the dates in-between. I then loop over the list and check if the date is a monday(1) and if it matches the dow value in the db (1). I then assign the date to that event and add it to a class object and make a list of the class objects.

Essentially each event has an individual date assigned with the same start and end time. Any time and event is resized it will update the base event in the database and therefore all events are updated. My solution is in C#.

Table structure:

id  event_id  startTime  endTime  startDate             endDate                 dow
2   22        12PM       01PM     3/12/2018 12:00:00 AM 10/15/2018 12:00:00 AM  1

while (reader.Read())
        {

            int dow;
            DateTime startTime;
            DateTime endTime;
            DateTime newstartdate;
            DateTime newenddate;

            var datelist = new List<DateTime>();
            DateTime tmpdate;

            for (int i = 0; i < end.Subtract(start).Days; i++)
            {
                tmpdate = start.AddDays(i);
                datelist.Add(tmpdate);
            }

            startTime = (DateTime)reader["startTime"];
            endTime = (DateTime)reader["endTime"];
            dow = (int)reader["dow"];

            foreach (DateTime day in datelist.ToList())
            {
                if((int)day.DayOfWeek == dow)
                {
                    CalendarEvent cevent = new CalendarEvent();

                    newstartdate = new DateTime(day.Year, day.Month, day.Day, startTime.Hour, startTime.Minute, 0);
                    newenddate = new DateTime(day.Year, day.Month, day.Day, endTime.Hour, endTime.Minute, 0);

                    cevent.id = (int)reader["event_id"];
                    cevent.title = (string)reader["ModuleName"];
                    cevent.description = (string)reader["Lecturer"];
                    cevent.start = newstartdate;
                    cevent.end = newenddate;
                    DateTime startDate = (DateTime)reader["startDate"];
                    ceventlist.start = startDate.ToString("yyyy-MM-dd");
                    DateTime endDate = (DateTime)reader["EndDate"];
                    ceventlist.end = endDate.ToString("yyyy-MM-dd");
                    datelist.Remove(day);



                    cevent.ranges = new List<CalendarEventList>();
                    cevent.ranges.Add(ceventlist);
                    events.Add(cevent);
                }
            }