webdad3 webdad3 - 7 days ago 6
Javascript Question

jquery FullCalendar - items being duplicated

I asked this question about a month ago and got my answer:

jquery FullCalendar using MVC and JSON

However, now I am seeing duplicates when I switch between months:
duplication of events

My javaScript code is:

var source = '../calendar/PostCalendarData';
$(document).ready(function () {

var events = [];
$('#calendar').fullCalendar('removeEvents');
$('#calendar').fullCalendar({
events: function(start, end, timezone, callback) {
$.ajax({
url: source,
type: 'POST',
data: {
custom_param1: '',
custom_param2: ''
},
success: function (doc) {
$.each(doc, function (index, element) {
events.push(element);
});
callback(events);
}
});
}

});
});


I'm populating the calendar using a stored procedure (located here: ../calendar/PostCalendar).

Is there something I need to do to clear out the calendar for each month?

I'm including the PostCalendar method here:

[HttpPost]
public ActionResult PostCalendarData()
{

SqlParameter param1 = new SqlParameter("@filterValue", "");
var calAssignments = db.Database.SqlQuery<calendarAssignment>(
"exec getCalendarInfo_v2 @filterValue ", param1).ToList<calendarAssignment>();

List<calendarEvent> calEvents = new List<calendarEvent>();
foreach (calendarAssignment item in calAssignments)
{
string[] splitDates = item.futureDates.Split(',');
foreach(string s in splitDates)
{
calendarEvent calEvent = new calendarEvent();
calEvent.title = item.name + " : " + item.chore;
calEvent.description = item.chore;

DateTime _futureDate;
_futureDate = DateTime.Parse(s);
calEvent.start = _futureDate.ToString("yyyy-MM-dd");
calEvents.Add(calEvent);
}
}


SqlParameter paramDaily = new SqlParameter("@filterValue", "daily");

var calAssignmentsDaily = db.Database.SqlQuery<calendarAssignment>(
"exec getCalendarInfo @filterValue ", paramDaily).ToList<calendarAssignment>();


foreach (calendarAssignment item in calAssignmentsDaily)
{
string[] splitDates = item.futureDates.Split(',');
foreach (string s in splitDates)
{
calendarEvent calEvent = new calendarEvent();
calEvent.title = item.name + " : " + item.chore;
calEvent.description = item.chore;

DateTime _futureDate;
_futureDate = DateTime.Parse(s);
calEvent.start = _futureDate.ToString("yyyy-MM-dd");
calEvents.Add(calEvent);
}
}

return Json(calEvents);
}


I have also verified that calEvents in the C# code always returns the same number. So it appears that it is specifically related to the javascript calendar.

Answer

Okay, first let's go over your code:

var events = []; // array declared in global-ish scope
$('#calendar').fullCalendar('removeEvents'); // Calling the remove method before FC is initialized (this should give an error, no?)
$('#calendar').fullCalendar({ // Creating the FC
    events: function(start, end, timezone, callback) { // Defining the event source as a function
        $.ajax({ // This is called every time the FC needs new events
            url: source, 
            type: 'POST', 
            data: { 
                custom_param1: '', 
                custom_param2: '' 
            }, 
            success: function (doc) { // This is called every time the ajax call finishes
                $.each(doc, function (index, element) {
                    events.push(element); // Push events into your event array
                });
                callback(events); // add ALL the events in the event array to the FC
            } 
        }); 
    }

});

So this is what's happening:

  1. FC initializes and fetches events - so far, so good.
  2. FC's view is changed to the next month and it fetches more events. Now your events array contains both this month's and last months events.
  3. FC's view is changed back to the previous month. Events are fetched and added to the same event array. Now you have duplicates.

You should either scope the event array inside the success handler like:

success: function (doc) { 
    var events = [];
    $.each(doc, function (index, element) {
        events.push(element); 
    });
    callback(events);
} 

or just empty the array in the success handler.

Better yet

Don't use the custom ajax call to get events. Use one of the built in methods. For example, the JSON Feed method should do what you want.

events: { // Automatically fetches data if your script is set up right.
    url: source,
    type: 'POST', // Ajax url looks like /source?start=2013-12-01&end=2014-01-12
                 // Note: it includes dates.
    data: {
        custom_param1: '',
        custom_param2: ''
    },
    error: function() {
    }
}

And if the JSON returned by your script doesn't perfectly fit FC's format, use eventDataTransform:

function( eventData ) { // Your JSON script should still return an array
                       // This function is called once per array item (event)
    eventData.title = eventData.name; // For example
    return eventData;
}
Comments