Events and AsyncQuery from SharePoint 2013 list - fullcalendar

I'm using a SharePoint 2013 list as the events source. Nothing special there as it's used as a data table.
I'm using the Client Javascript API and getting items (from the list) with the function executeQueryAsync
Here is the code
var clientContext = new SP.ClientContext.get_current();
oWebsite = clientContext.get_web();
var oList = oWebsite.get_lists().getByTitle('EventsList');
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml("<View><ViewFields><FieldRefName='ID' /><FieldRef Name='Title' /><FieldRef Name='EventDate' /><FieldRef Name='EndDate' /></ViewFields><Query><Where><And><Geq><FieldRef Name='EventDate'/><Value Type='DateTime'>" + startDate + "</Value></Geq><Leq><FieldRef Name='EndDate'/><Value Type='DateTime'>" + endDate + "</Value></Leq></And></Where></Query></View>");
this.collListItem = oList.getItems(camlQuery);
clientContext.load(collListItem);
clientContext.executeQueryAsync(Function.createDelegate(this, this.onQuerySucceeded), Function.createDelegate(this, this.onQueryFailed));
The problem I'm facing is that the deletegatefunction triggers only when the AsyncQuery is complete. The onQuerySucceeded function is as followed
function onQuerySucceeded(sender, args) {
var listItemInfo = '';
var listItemEnumerator = collListItem.getEnumerator();
eventSourceArray.push({ title: 'Test Event', start: '2017-02-08' });
while (listItemEnumerator.moveNext()) {
alert(listItemEnumerator);
var oListItem = listItemEnumerator.get_current();
listItemInfo += '\nID: ' + oListItem.get_id() +
alert(oListItem.get_item('Title'));
}
}
The "alert" is only for testing purpose. If I put alerts into this function, it is displayed. However the event that is pushed into the source is not displayed. I'm looking for a way to refresh the calendar once the query is complete.
UPDATE:
The events I want to show are populated asynchronously in the eventSourceArray which is used as the Events source (see the code below)
jQuery('#calendrier').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultDate: today,
lang: 'fr-ca',
buttonIcons: true,
weekNumbers: false,
editable: false,
eventLimit: true,
events: eventSourceArray
});
Now I'm looking for a way to reload the calendar or have the added events in the Array to show even if the page is already loaded.
UPDATE:
I tried this, but it has no effect. https://fullcalendar.io/docs/event_data/addEventSource/
jQuery('#calendrier').fullCalendar('refetchEventSources', eventSourceArray);
I added an alert to display the length of the array (eventSourceArray) and the items are all there)
UPDATE:
Tried resetting the events with my array
events: eventSourceArray
and then calling the refetchEvents https://fullcalendar.io/docs/event_data/refetchEvents/
jQuery('#calendrier').fullCalendar('refetchEvents')

This did the trick at the end of the OnQuerySucceed function
jQuery('#calendrier').fullCalendar('removeEventSources', eventSourceArray)
jQuery('#calendrier').fullCalendar('addEventSource', eventSourceArray)

Related

FullCalendar plugin not rendering events on calendar

I am using fullCalendar plugin to display events from ASP.NET ASMX web service. JSON data is fetched correct and displayed ok in the console. But events are not rendered on the calendar view. What am I missing?
$('#divcalendar').fullCalendar({
defaultDate: '2018-03-12',
editable: true,
eventLimit: true, // allow "more" link when too many events
events: function (start, end, timezone,callback) {
$.ajax({
type: "POST",
url: 'Webservice.asmx/ListEvents',
cache: false,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
var event = [];
$(data.d).each(function () {
event.push({
title: this.Title,
start: this.Start,
end: this.End
});
});
console.log(event);
callback(event);
},
error: function (jqXHR, textStatus, errorThrown) {
alert('There was an error');
}
});
}
});
[WebMethod]
public CalendarEvent[] ListEvents()
{
DateTime epoc = new DateTime(1970, 1, 1);
return new CalendarEvent[]
{
new CalendarEvent { Title = "Event 1", Start = new DateTime(2018,3,9,16,0,0).Subtract(epoc).TotalSeconds, End = new DateTime(2018,3,9,17,0,0).Subtract(epoc).TotalSeconds},
new CalendarEvent { Title = "Event 2", Start = new DateTime(2018,3,12,12,0,0).Subtract(epoc).TotalSeconds, End = new DateTime(2018,3,12,13,0,0).Subtract(epoc).TotalSeconds}
};
}
Console output from webservice
{"d":[{"__type":"CalendarEvent","End":1520614800,"Start":1520611200,"Title":"Event 1"},{"__type":"CalendarEvent","End":1520859600,"Start":1520856000,"Title":"Event 2"}]}
I think your dates are being entered into the calendar, but not in the place you intended.
Although you haven't mentioned it explicitly, I would strongly suspect that the timestamps you're outputting for your start and end dates are specified in seconds.
Now, fullCalendar uses momentJS to parse any date strings or timestamps supplied to it. Alternatively it can accept ready-made momentJS or JS Date objects.
momentJS can parse timestamps automatically through the momentJS constructor (which fullCalendar is calling when it receives your timestamp value), but it assumes the value is given in milliseconds, not seconds.
Therefore when you supply it with, for instance, 1520611200 (the start date of your first event), it interprets that in milliseconds and the resulting date is 1970-01-18 14:23:31.
If you want to specify the date in seconds you have to use the moment.unix() method instead. Using this method, your timestamp is instead interpreted as 2018-03-09 16:00:00, which I assume is what you intended.
See http://jsfiddle.net/Loccoxds/1/ for a demo to see the difference in how momentJS parses one of your values.
To get your code working, the simplest way is to do this:
success: function (data) {
var event = [];
$(data.d).each(function () {
event.push({
title: this.Title,
start: moment.unix(this.Start),
end: moment.unix(this.End)
});
});
console.log(event);
callback(event);
},
This way, you supply a ready-made momentJS object to fullCalendar, having correctly parsed the timestamp.
See http://momentjs.com/docs/#/parsing/unix-timestamp-milliseconds/ for more details about parsing timestamps in momentJS
P.S. Alternatively of course you could change your asmx service to output the dates in a format momentJS can parse automatically, such as a timestamp in milliseconds, or an ISO8601-formatted date string - see http://momentjs.com/docs/#/parsing/string/ for details of that.
P.P.S. ASMX is pretty much a legacy technology within .NET now. You should consider using WCF or Web API instead. Microsoft recommends not to create new code using ASMX.

Fullcalendar: save external events immediately in SQL db

I searched Stackoverflow for an answer to my question: How to save dropped external events immediately to the database. Adding and updating events through the dialog works fine. Dragged external events are rendered fine.
This is the code I use in the eventReceive function. The first alert to show the event data is correct, but the second is never reached.
eventReceive: function (event, delta, revertFunc) {
alert(event.title + " was dropped on " + event.start.format()); //REPLACE WITH AJAX TO SAVE EVENT DATA
var eventToAdd = {
title: event.title,
description: "Unknown",
start: event.start.format,
end: event.end.format,
allDay: isAllDay(event.StartDate, event.EndDate)
};
if (checkForSpecialChars(eventToAdd.title) || checkForSpecialChars(eventToAdd.description)) {
alert("please enter characters: A to Z, a to z, 0 to 9, spaces");
}
else {
alert(event.title + " was dropped on " + event.start.format());
PageMethods.addEvent(eventToAdd, addSuccess);
}
},
I digged somewhat deeper and as far as I can tell, after the var eventToAdd JQuery 3.3.1 triggers the same functions over and over again as soon as the mouse is hovered over any element in the page. Functions involved are: matchFromGroupMatchers, elementmatcher, prefilter and Sizzle. The javascript of fullcalendar does not resume.
It seems the variable eventToAdd was in use. Changing it to a different name solved it. I have it now this way:
eventReceive: function (event) {
// alert(event.title + " was dropped on " + event.start.format());
var eventAdd = {
start: event.start.format(),
end: event.end.format(),
title: event.title,
description: "Onbekend",
hwType: "Proefwerk",
};
PageMethods.addEvent(eventAdd, addSuccess);
},

fullcalendar with resourceDay, update list of resources

I am using fullcalendar v1.5.4 with the resourceDay view (https://gist.github.com/anonymous/9c9ce0d84a6a73080177). My problem is when I am trying to update the list of resources. I can just run setCalendar() but it's quite a big and resource expensive function:
setCalendar = function (defaultView, element, currentDate) {
myCal = $(element);
myCal.fullCalendar({
minTime: '07:00:00',
maxTime: '23:59:00',
cache: true,
editable: true,
eventStartEditable: true,
eventDurationEditable: true,
...
resources: [ resourcesArray ],
dayClick: function (date, event, t, r) {
...
}
...
});
}
Running all of this code every time I want to update the columns of the resourceDay view is too expensive so I am trying to update only the list of columns (resources) and rerender them. In the function ResourceManager of the gist that I linked above (row 1257) you can see that I have tried to lift the function that populates the list of resources. By adding t._addResourceSources = _addResourceSources; and then calling on it from this function:
updateCalendar = function () {
myCal.fullCalendar('_addResourceSources', resourcesArray);
};
This is printing the new list to the console (row 1305) but I need assistance with rerendering it so the calendar actually uses the new list of resources.
Try running myCal.fullCalendar( 'rerenderEvents' );
http://fullcalendar.io/docs1/event_rendering/rerenderEvents/
It may not work though, I don't know how resources work exactly and I'm more familiar with the v2 of fullCalendar.

Timezone for dropped event in FullCalendar

I'm implementing fullcalendar and struggling with a timezone issue.
Here is the code:
$('#calendar').fullCalendar({ //re-initialize the calendar
header: h,
defaultView: 'agendaWeek', // change default view with available options from http://arshaw.com/fullcalendar/docs/views/Available_Views/
slotMinutes: 15,
editable: true,
lang: 'pl',
timezone: 'Europe/Warsaw',
droppable: true, // this allows things to be dropped onto the calendar !!!
drop: function(date, allDay) { // this function is called when something is dropped
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// assign it the date that was reported
copiedEventObject.start = date;
var endDate = new Date(date);
endDate.setMinutes(endDate.getMinutes() + 70);
copiedEventObject.end = endDate;
alert(date);
alert(endDate);
//copiedEventObject.allDay = allDay;
copiedEventObject.className = $(this).attr("data-class");
// render the event on the calendar
// the last `true` argument determines if the event "sticks" (http://arshaw.com/fullcalendar/docs/event_rendering/renderEvent/)
$('#calendar').fullCalendar('renderEvent', copiedEventObject, true);
// is the "remove after drop" checkbox checked?
if ($('#drop-remove').is(':checked')) {
// if so, remove the element from the "Draggable Events" list
$(this).remove();
}
},
});
If I create new event by dropping it what I get is a date-time with GMT timezone, where as I should be set to CET, please help how to rectify the drop event time zone setting.
I had a similar issue. Setting the calendar property to ** timeZone: 'none' **. You will need to specify the timezone short codes in the datetime string otherwise.

Get dates during fullcalendar initializing

I'm using eventSources method to initialize FullCalendar jQuery plugin.
eventSources: [
initEvents(visibleStartDate, visibleEndDate)
]
where initEvents is and ajax call to jsp page that returns json object representing events to be rendered. It works great but now I'd like to fetch the event only for the dates visible on calendar. I read in documentation that I could use visStart and visEnd on View object to get the start and end day of the calendar, however I don't know how to get that information at the time I initialize my eventSources. Is there a way? Thank you in advance for your responses.
Eric
It turns out that fullcalendar plugin will add start and end HTTP parameters when calendar sources are fetched externally. Full details are described in documentation here: http://arshaw.com/fullcalendar/docs/event_data/events_json_feed/
My code (mix of javascript, JSP, JSF):
FullCalendal initialization:
page.view.calendar.fullCalendar(
{
....
eventSources: [
page.control.initEventSources(#{sessionBean.myCalendar.calendarConfgIdNbr},'Approved'),
page.control.initCalendarHolidays(#{sessionBean.myCalendar.calendarConfgIdNbr})],
....
});
2. My javascript function:
page.control.initEventSources:
var page = {
control : {
initEventSources : function(calConfId, status) {
return {
url: '/oceportal/tom/data/bookings.jsp',
type: 'POST',
data: { calConfId: calConfId, bookingStatus: status, loggedInId: "#{sessionBean.loggedInId}", },
success: function(data) { },
error: function() { alert('there was an error while fetching events!'); },
color: 'none',
textColor: page.colorConfig[status]
};
}
}
}
My JSP snippet (to retrieve first and last visible day):
String start = request.getParameter("start");
Date startDt = new Date(Long.parseLong(start)*1000);
String end = request.getParameter("end");
Date endDt = new Date(Long.parseLong(end)*1000);
Hope it helps someone.

Resources