Display Events from a SharePoint Calendar Using jQuery and FullCalendar

Web Design & Development
This entry is part 1 of 2 in the series Building a Better SharePoint Calendar.

As part of a large department site redesign project, I wanted to implement a better calendar solution than what MOSS 2007 gives you OOTB. I remembered coming across the FullCalendar jQuery plugin a while back, so I decided to try using it with the calendar on my department’s site. I haven’t tested this in SharePoint 2010, but it should work just fine regardless of the version (just verify all of the column references in case any of them are named differently).

Prepping the Resources

I downloaded the latest FullCalendar package, unzipped the file, and uploaded the CSS and JavaScript files to a document library on my site. I like to use a library called WebResources and add a choice column with options for “CSS,” “Image,” “JavaScript,” and “jQuery” so I can keep track of all of my various resources in one place, with versioning.

Screenshot of FullCalendar Resources in the WebResources Library
I keep all of my resources in a "WebResources" document library grouped by the type of resource.

Once the files were uploaded, I copied the calendar.aspx page and renamed it CalendarCustom.aspx in SharePoint Designer (SPD). Then I switched back to the web UI, went to the calendar settings, and modified the duplicate “Calendar” view so I could rename it and set it as the default (this is the view that will contain our custom calendar). Next I opened that view and hid the default list view web part for the calendar.

The last step in prepping the page was to open it in SPD and add references to the CSS and JavaScript files that the calendar will need just below the <asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server"> tag on the page (you could also put them in a Content Editor Web Part):

Screenshot of CSS and Script References for FullCalendar
Load the CSS and JavaScript references on the page. This can be done in a Content Editor Web Part, but I prefer to add them in the PlaceHolderMain section.

Setting Up the Data View Web Part

To make this happen, I used a Data View Web Part (DVWP) to output the necessary JavaScript for the plugin to generate the calendar. I selected the web part zone and inserted a new DVWP. I chose the Calendar list as my data source, selected the Title field and inserted it as a “Multiple Item View.”

Screenshot of Calendar Data Source Displayed as a Multiple Item View
Insert a DVWP with the calendar as the data source, and insert the Title field as a "Multiple Item View."

I didn’t want to bog down the browser by loading hundreds of really old events, so I set a filter on the DVWP so that only events with a start time greater than or equal to today minus 90 days would be displayed (see this post for more information on setting up CAML query offsets). This allows people to view events up to three months in the past, as well as current and future events. I also sorted the events by start time in ascending order.

Paging doesn’t really work well with this solution because it uses URL query string parameters, so I set it to limit the total items returned to 1,000 (in a future post I may explore paging to see if there is any value in using paging with this plugin by hooking into those query string parameters). This may prove to be too large if the calendar is populated with that many events, but in general there aren’t more than 20-30 future events scheduled at a given time.

Once I got the DVWP web part on the page I changed the layout to use the bulleted list style (this is the easiest style to work with IMO).

Screenshot of FullCalendar DVWP Settings
I set up the DVWP using the Common Data View Tasks menu before switching to code view.

Digging into the XSLT

From this point on I edited the XSLT using only the code view. Once you start doing this, SPD has a tough time keeping up with your customizations, so be sure that you’ve set up your filters, sorting, and paging limits before moving on.

Once in code view, go ahead and format the <XSL> stylesheet so everything is indented well; SPD tends to use some weird indenting when it generates the code through the UI.

In the dvt_1 template I created a new parameter called RowCount that simply counts the number of rows. This will let us identify the last row for our JSON (the reason for this will be explained shortly).

<xsl:variable name="RowCount" select="count($Rows)" />

In this same template I replaced the <ul> elements with an XSL variable called Events that will hold the JSON portion of the JavaScript for the calendar. I also inserted <xsl:with-param name="RowCount" select="$RowCount" /> into the call to the dvt_1.body template so we can use that value later.

<xsl:template name="dvt_1">
	<xsl:variable name="dvt_StyleName">BulTitl</xsl:variable>
	<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
	<xsl:variable name="RowLimit" select="1000" />
	<xsl:variable name="RowCount" select="count($Rows)" />
	<xsl:variable name="Events">
		<xsl:call-template name="dvt_1.body">
			<xsl:with-param name="Rows" select="$Rows" />
			<xsl:with-param name="FirstRow" select="1" />
			<xsl:with-param name="LastRow" select="$RowLimit" />
			<xsl:with-param name="RowCount" select="$RowCount" />
		</xsl:call-template>
	</xsl:variable>
</xsl:template>

After the Events variable, I added the <script> element and the actual JavaScript that will generate the calendar. The script defines a function called myCalendar that executes the FullCalendar plugin using the options that I specified. When it’s time for the function to load the JSON for the events, I inserted an <xsl:value-of select="$Events" /> which will insert the Events variable that I created. The last part of the JavaScript is the jQuery $(document).ready function, which executes the myCalendar function once the page loads. Finally, I inserted a <div> element with an ID of “calendar” for the FullCalendar plugin to insert the calendar into.

<xsl:template name="dvt_1">
	<xsl:variable name="dvt_StyleName">BulTitl</xsl:variable>
	<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
	<xsl:variable name="RowLimit" select="1000" />
	<xsl:variable name="RowCount" select="count($Rows)" />
	<xsl:variable name="Events">
		<xsl:call-template name="dvt_1.body">
			<xsl:with-param name="Rows" select="$Rows" />
			<xsl:with-param name="FirstRow" select="1" />
			<xsl:with-param name="LastRow" select="$RowLimit" />
			<xsl:with-param name="RowCount" select="$RowCount" />
		</xsl:call-template>
	</xsl:variable>
	<script type="text/javascript">
		function myCalendar() {
			$('#calendar').fullCalendar({
				header: {
					left: 'prev,next today',
					center: 'title',
					right: 'month,agendaWeek,agendaDay'
				},
				editable: false,
				events: [
					<xsl:value-of select="$Events" />
				]
			});
		}
		$(document).ready(function(){
			// Execute the calendar function
			myCalendar();
		});
	</script> <p><a href="NewForm.aspx" title="Add an event to the calendar.">Add Event</a></p>
	<div id="calendar">
	</div><!-- #calendar -->
</xsl:template>

The only modification I made to the dvt_1.body template was to receive the RowCount parameter and then pass it along to the dvt_1.rowview template.

<xsl:template name="dvt_1.body">
	<xsl:param name="Rows" />
	<xsl:param name="FirstRow" />
	<xsl:param name="LastRow" />
	<xsl:param name="RowCount" />
	<xsl:for-each select="$Rows">
		<xsl:variable name="dvt_KeepItemsTogether" select="false()" />
		<xsl:variable name="dvt_HideGroupDetail" select="false()" />
		<xsl:if test="(position() >= $FirstRow and position() <= $LastRow) or $dvt_KeepItemsTogether">
			<xsl:if test="not($dvt_HideGroupDetail)" ddwrt:cf_ignore="1">
				<xsl:call-template name="dvt_1.rowview">
					<xsl:with-param name="RowCount" select="$RowCount" />
				</xsl:call-template>
			</xsl:if>
		</xsl:if>
	</xsl:for-each>
</xsl:template>

For the dvt_1.rowview template, I completly gutted it (we don’t need anything in it right now), then I created a number of variables to hold values for the year, month, day, hour, and minute of the Start Time and End Time for each event. Months are zero-indexed in JavaScript so I had to subtract 1 from the value of the month (e.g. January needs to be “0” in JavaScript, not “1”).

<xsl:template name="dvt_1.rowview">
	<xsl:param name="RowCount" />
	<xsl:variable name="startYear" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'yyyy')" />
	<xsl:variable name="startMonth" select="number(ddwrt:FormatDateTime(string(@EventDate), 1033, 'MM'))-1" />
	<xsl:variable name="startDay" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'dd')" />
	<xsl:variable name="startHour" select="substring-before(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="startMinute" select="substring-after(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endYear" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'yyyy')" />
	<xsl:variable name="endMonth" select="number(ddwrt:FormatDateTime(string(@EndDate), 1033, 'MM'))-1" />
	<xsl:variable name="endDay" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'dd')" />
	<xsl:variable name="endHour" select="substring-before(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endMinute" select="substring-after(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
</xsl:template>

After this I set up an <xsl:choose> section. Remember how I mentioned that we needed to identify the last row? In order for the JavaScript to work properly, the last event in the JSON can’t have a trailing comma or it won’t be parsed properly. To manage this, I’m using a bit of logic to test if the event is the last row. If it is, then no trailing comma is output. All of the other events up to the last one do have a trailing comma.

<xsl:template name="dvt_1.rowview">
	<xsl:param name="RowCount" />
	<xsl:variable name="startYear" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'yyyy')" />
	<xsl:variable name="startMonth" select="number(ddwrt:FormatDateTime(string(@EventDate), 1033, 'MM'))-1" />
	<xsl:variable name="startDay" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'dd')" />
	<xsl:variable name="startHour" select="substring-before(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="startMinute" select="substring-after(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endYear" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'yyyy')" />
	<xsl:variable name="endMonth" select="number(ddwrt:FormatDateTime(string(@EndDate), 1033, 'MM'))-1" />
	<xsl:variable name="endDay" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'dd')" />
	<xsl:variable name="endHour" select="substring-before(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endMinute" select="substring-after(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
	<xsl:choose>
		<xsl:when test="position() != $RowCount">
			<xsl:call-template name="dvt_EventInfo">
				<xsl:with-param name="startYear" select="$startYear" />
				<xsl:with-param name="startMonth" select="$startMonth" />
				<xsl:with-param name="startDay" select="$startDay" />
				<xsl:with-param name="startHour" select="$startHour" />
				<xsl:with-param name="startMinute" select="$startMinute" />
				<xsl:with-param name="endYear" select="$endYear" />
				<xsl:with-param name="endMonth" select="$endMonth" />
				<xsl:with-param name="endDay" select="$endDay" />
				<xsl:with-param name="endHour" select="$endHour" />
				<xsl:with-param name="endMinute" select="$endMinute" />
			</xsl:call-template>,
		</xsl:when>
		<xsl:otherwise>
			<xsl:call-template name="dvt_EventInfo">
				<xsl:with-param name="startYear" select="$startYear" />
				<xsl:with-param name="startMonth" select="$startMonth" />
				<xsl:with-param name="startDay" select="$startDay" />
				<xsl:with-param name="startHour" select="$startHour" />
				<xsl:with-param name="startMinute" select="$startMinute" />
				<xsl:with-param name="endYear" select="$endYear" />
				<xsl:with-param name="endMonth" select="$endMonth" />
				<xsl:with-param name="endDay" select="$endDay" />
				<xsl:with-param name="endHour" select="$endHour" />
				<xsl:with-param name="endMinute" select="$endMinute" />
			</xsl:call-template>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>

Notice that I am calling another template called dvt_EventInfo for both conditions of the <xsl:choose> instead of outputting the actual JSON. This lets me re-use the same template for both conditions rather than writing out the XSLT for each condition. The two conditions look almost identical, but if you look close, you’ll see that after the closing tag of the <xsl:call-template> in the <xsl:when> section I included a trailing comma because that condition is used when the event is not the last row.

The dvt_EventInfo template itself outputs the JSON required by the FullCalendar plugin. The “title” value could be problematic because users might use a character in the @Title field that screws up the JavaScript function (like an apostrophe). For now I decided to remove any apostrophes (referenced with the $dvt_apos parameter) using the translate XPath function. A more robust solution would be to pass the @Title field into a recursive XSL template that removes any characters that would be a problem for the JavaScript. I’ll probably tackle that in the next post for this series.

I also used a bit of logic to determine if the event should be an all day event. If it has a start time of 12:00 a.m. I consider it an all day event (you may want to use different criteria for this, but I like this option because it takes into account the fact that some users won’t remember to check the box indicating an all day event and will instead set the start and end times to 12:00 a.m. and 11:55 p.m. respectively; it also allows for use on non-calendar lists that don’t have an all-day option). Otherwise I indicate that it is not an all day event.

<xsl:template name="dvt_EventInfo">
	<xsl:param name="startYear" />
	<xsl:param name="startMonth" />
	<xsl:param name="startDay" />
	<xsl:param name="startHour" />
	<xsl:param name="startMinute" />
	<xsl:param name="endYear" />
	<xsl:param name="endMonth" />
	<xsl:param name="endDay" />
	<xsl:param name="endHour" />
	<xsl:param name="endMinute" />
	{
		title: '<xsl:value-of select="translate(@Title, $dvt_apos, '')" />',
		start: new Date(<xsl:value-of select="concat($startYear, ', ', $startMonth, ', ', $startDay, ', ' , $startHour, ', ', $startMinute)" />),
		end: new Date(<xsl:value-of select="concat($endYear, ', ', $endMonth, ', ', $endDay, ', ', $endHour, ', ', $endMinute)" />),
		url: '<xsl:value-of select="concat('/', @FileDirRef, '/DispForm.aspx?ID=', @ID)" />',
		<xsl:choose>
			<xsl:when test="$startHour != '00' and $endHour !='00'">
				allDay: false
			</xsl:when>
			<xsl:otherwise>
				allDay: true
			</xsl:otherwise>
		</xsl:choose>
	}
</xsl:template>

The End Result

Here is the entire XSL stylesheet that I used:

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="dvt_apos">'</xsl:param>
<xsl:param name="Today">CurrentDate</xsl:param>
<xsl:variable name="dvt_1_automode">0</xsl:variable>

<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">
<xsl:call-template name="dvt_1"/>
</xsl:template>

<xsl:template name="dvt_1">
	<xsl:variable name="dvt_StyleName">BulTitl</xsl:variable>
	<xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
	<xsl:variable name="RowLimit" select="1000" />
	<xsl:variable name="RowCount" select="count($Rows)" />
	<xsl:variable name="Events">
		<xsl:call-template name="dvt_1.body">
			<xsl:with-param name="Rows" select="$Rows" />
			<xsl:with-param name="FirstRow" select="1" />
			<xsl:with-param name="LastRow" select="$RowLimit" />
			<xsl:with-param name="RowCount" select="$RowCount" />
		</xsl:call-template>
	</xsl:variable>
	<script type="text/javascript">
		function myCalendar() {
			$('#calendar').fullCalendar({
				header: {
					left: 'prev,next today',
					center: 'title',
					right: 'month,agendaWeek,agendaDay'
				},
				editable: false,
				events: [
					<xsl:value-of select="$Events" />
				]
			});
		}
		$(document).ready(function(){
			// Execute the calendar function
			myCalendar();
		});
	</script> <p><a href="NewForm.aspx" title="Add an event to the calendar.">Add Event</a></p>
	<div id="calendar">
	</div><!-- #calendar -->
</xsl:template>

<xsl:template name="dvt_1.body">
	<xsl:param name="Rows" />
	<xsl:param name="FirstRow" />
	<xsl:param name="LastRow" />
	<xsl:param name="RowCount" />
	<xsl:for-each select="$Rows">
		<xsl:variable name="dvt_KeepItemsTogether" select="false()" />
		<xsl:variable name="dvt_HideGroupDetail" select="false()" />
		<xsl:if test="(position() >= $FirstRow and position() <= $LastRow) or $dvt_KeepItemsTogether">
			<xsl:if test="not($dvt_HideGroupDetail)" ddwrt:cf_ignore="1">
				<xsl:call-template name="dvt_1.rowview">
					<xsl:with-param name="RowCount" select="$RowCount" />
				</xsl:call-template>
			</xsl:if>
		</xsl:if>
	</xsl:for-each>
</xsl:template>

<xsl:template name="dvt_1.rowview">
	<xsl:param name="RowCount" />
	<xsl:variable name="startYear" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'yyyy')" />
	<xsl:variable name="startMonth" select="number(ddwrt:FormatDateTime(string(@EventDate), 1033, 'MM'))-1" />
	<xsl:variable name="startDay" select="ddwrt:FormatDateTime(string(@EventDate), 1033, 'dd')" />
	<xsl:variable name="startHour" select="substring-before(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="startMinute" select="substring-after(ddwrt:FormatDateTime(string(@EventDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endYear" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'yyyy')" />
	<xsl:variable name="endMonth" select="number(ddwrt:FormatDateTime(string(@EndDate), 1033, 'MM'))-1" />
	<xsl:variable name="endDay" select="ddwrt:FormatDateTime(string(@EndDate), 1033, 'dd')" />
	<xsl:variable name="endHour" select="substring-before(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
	<xsl:variable name="endMinute" select="substring-after(ddwrt:FormatDateTime(string(@EndDate), 1033, 'HH:mm'), ':')" />
	<xsl:choose>
		<xsl:when test="position() != $RowCount">
			<xsl:call-template name="dvt_EventInfo">
				<xsl:with-param name="startYear" select="$startYear" />
				<xsl:with-param name="startMonth" select="$startMonth" />
				<xsl:with-param name="startDay" select="$startDay" />
				<xsl:with-param name="startHour" select="$startHour" />
				<xsl:with-param name="startMinute" select="$startMinute" />
				<xsl:with-param name="endYear" select="$endYear" />
				<xsl:with-param name="endMonth" select="$endMonth" />
				<xsl:with-param name="endDay" select="$endDay" />
				<xsl:with-param name="endHour" select="$endHour" />
				<xsl:with-param name="endMinute" select="$endMinute" />
			</xsl:call-template>,
		</xsl:when>
		<xsl:otherwise>
			<xsl:call-template name="dvt_EventInfo">
				<xsl:with-param name="startYear" select="$startYear" />
				<xsl:with-param name="startMonth" select="$startMonth" />
				<xsl:with-param name="startDay" select="$startDay" />
				<xsl:with-param name="startHour" select="$startHour" />
				<xsl:with-param name="startMinute" select="$startMinute" />
				<xsl:with-param name="endYear" select="$endYear" />
				<xsl:with-param name="endMonth" select="$endMonth" />
				<xsl:with-param name="endDay" select="$endDay" />
				<xsl:with-param name="endHour" select="$endHour" />
				<xsl:with-param name="endMinute" select="$endMinute" />
			</xsl:call-template>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>

<xsl:template name="dvt_EventInfo">
	<xsl:param name="startYear" />
	<xsl:param name="startMonth" />
	<xsl:param name="startDay" />
	<xsl:param name="startHour" />
	<xsl:param name="startMinute" />
	<xsl:param name="endYear" />
	<xsl:param name="endMonth" />
	<xsl:param name="endDay" />
	<xsl:param name="endHour" />
	<xsl:param name="endMinute" />
	{
		title: '<xsl:value-of select="translate(@Title, $dvt_apos, '')" />',
		start: new Date(<xsl:value-of select="concat($startYear, ', ', $startMonth, ', ', $startDay, ', ' , $startHour, ', ', $startMinute)" />),
		end: new Date(<xsl:value-of select="concat($endYear, ', ', $endMonth, ', ', $endDay, ', ', $endHour, ', ', $endMinute)" />),
		url: '<xsl:value-of select="concat('/', @FileDirRef, '/DispForm.aspx?ID=', @ID)" />',
		<xsl:choose>
			<xsl:when test="$startHour != '00' and $endHour !='00'">
				allDay: false
			</xsl:when>
			<xsl:otherwise>
				allDay: true
			</xsl:otherwise>
		</xsl:choose>
	}
</xsl:template>

</xsl:stylesheet>

You can probably drop this right into your DVWP once you set up the initial filters, sorting, and paging. Of course, if you do that, you miss out on all of the fun of typing it up and figuring out how it all works!

If everything is working properly, you get a nice looking calendar that is very responsive to user input. In a future post I’ll explore ways to enhance the calendar with drag-and-drop functionality and an easy way to create new events. If you want users to be able to create new events right now, you can insert a link to the NewForm.aspx page right before the <div id="calendar"></div> element in the dvt_1 template (I did this in the above XSLT).

Room for Improvement

Since implementing this simple solution, I’ve noticed several areas in which it could be improved. I’m actually using it in a very limited scope on a highly-customized site, so this solutions works very well for my department, but if you drop it into a standard SharePoint site you’ll run into some limitations:

  • It doesn’t allow for an elegant way to view all items (via paging or AJAX).
  • It doesn’t work with the date picker control above the quick launch.
  • It doesn’t include the usual toolbar controls for adding items, connecting to Outlook, creating alerts, subscribing to RSS feeds, or switching views.

Most of these issues are fairly minor and I think they can be overcome with a little digging into the FullCalendar documentation.

I also plan on making further enhancements. For example, this plugin supports drag-and-drop functionality, so I intend to incorporate that by using the SPServices plugin from @sympmarc to allow Outlook-like functionality for adding and modifying events. I’m also going to see if I can incorporate color-coding. Look for a future post with some of these improvements.

The reactions to this calendar so far have been very positive from our users within the department. Please let me know if you have any suggestions!

Series: Building a Better SharePoint Calendar


Comments

  1. Excellent post Josh! This mehthod of emitting JSON is extremely useful. We actually use the same calendar plugin and I can assure you, color coding; Connect To Outlook; & Paging/Viewing All Items w/ AJAX are all doable. I can't wait to read the rest of the series! Cheers, Matt
  2. Great post I've been looking for. One question though how does this handle reoccuring meetings? The issue I'm stuggling with is that since reoccuring meetings are stored as a single meeting in the calendar they only show up once. I've been exploring how to modify the CAML to pull all the dates, but I haven't been able to get it to work correctly.
    1. Recurring events are indeed a tricky issue because of how they are stored. I'll be looking into that in a future post.
      1. If it helps here is the CAML from the selectcommand attribute in the SharePoint:SPDataSource tag for the WebPart. This will pull all of the data necessary to do the reoccuring calcuations: TRUE I'm working on the logic to do the meeting calcuations in the XSL based on http://sharepoint.microsoft.com/blog/Pages/BlogPost.aspx?PageType=4&ListId={72C1C85B-1D2D-4A4A-90DE-CA74A7808184}&pID=761
        1. Check out part two: http://joshmccarty.com/2011/11/sharepoint-jquery-and-fullcalendar—now-with-spservices/
    2. I'm a little late to the party, but I didn't recieve any notifications. :/ To use SPServices and recurring events from a SharePoint calendar, take a look at Jim Bob's post on SPServices: http://spservices.codeplex.com/discussions/254560 This is production code and is being used with the same calendar plugin that Josh blogged about here. Cheers, Matt
  3. Amazing Post.. works like a charm. I have a small requirement change. I have a column"TotalTime" that i have added and i want sum of TotalTime to be show on each date and it should be a full day event. I am trying to mess with this from past few days. It would be really great if you could help me out with this. I tried the XSL Grouping method but i can see data in designer but it does not get populated in calendar. Thanks in advance
    1. Hi Varun, When you say you're seeing the data in designer, are you outputting it in some kind of table? To add the data to the calendar, you need to output it within the JSON that the data view web part is creating. Perhaps you can post the code you have so far on StackExchange or another forum and let me know where it's posted so I can take a look?
      1. Hey Josh, Thanks for your reply. I have uploaded the code on Stackoverflow. Link below http://stackoverflow.com/questions/9975062/using-muenchian-to-create-events-json-for-full-calendar Let me know if you require anything else i am using the muenchian method for grouping
  4. Hi Josh, Excellent post. I am working on the SharePoint calendar where I have to count number of events per day and show in it in the respective date. I think I can use CAML query. Please give me some ideas. Thank you Sri
    1. This sounds like a requirement that's beyond the scope of this article. Can you post your question to a forum and I'll take a look in greater detail (e.g. stackexchange)?
  5. Hi Josh, I can I use your article and your FullCalendar solution and get the output. As per your article I can get the solution like http://social.msdn.microsoft.com/Forums/getfile/98824 but I want the output like http://social.msdn.microsoft.com/Forums/getfile/98825. Thank you Sri
    1. Hi Sri, After looking into it a bit more I think that would require some serious re-engineering of the FullCalendar plugin. However, there is a fork of the FullCalendar on GitHub that might provide an alternative; it let's you specify a maximum number of events to display for each day in the month view, then renders a "View More" link to see all events for that day if there are more than the maximum number specified. Check it out at https://github.com/lyconic/fullcalendar/tree/view-more.
  6. thanks for sharing. my need is to display a 2nd webpart dataview of detail records derived with a query based upon the event selected. The event record contains order header due that day, want to show all order details upon event click. have found this most impossible with the standard calendar object as it does not support connections. Any chance with this object and using script ? thanks.
    1. This is essentially no longer a SharePoint web part once FullCalendar renders the calendar, so web part connections aren't going to work. What you could do is use AJAX to load the related order details on item click (I'd use SPServices for this) instead of opening the actual calendar item. Check out http://arshaw.com/fullcalendar/docs/mouse/eventClick/ for documentation on FullCalendar's event click callback and http://spservices.codeplex.com for documentation on using SPServices.

Comments are closed