SPServices Stories #15: Custom Client-side Calendar Query for Office 365 SharePoint Site Using SPServices jQuery Library

This entry is part 15 of 21 in the series SPServices Stories

Introduction

My friend and fellow MVP Becky Bertram (@beckybertram) recently acquiesced to my suggestion to try using SPServices to solve a challenge she had in rolling up calendar items across lists. I know it may often seem that since SPServices is my hammer that I always say to whack the nails with it, but sometimes it’s actually a good suggestion!

Becky wrote up a nice overview of her approach on her blog. It’s always interesting to see the differences in how people use SPServices. Becky built herself some great functions, which allows for better reuse over time. It amazes me sometimes how others end up with hundreds and hundreds of lines of code rather than coming up with generalized functions, as Becky does here. Sure, some SPServices users aren’t “developers”, but that doesn’t mean that they can’t learn from the examples and build stronger code for it.

Note that the REST services also let you access calendar items (or any other list items), but CAML gives you a better syntax to use with recurring events than I’m aware of in the REST interface. Yup, sometimes, I prefer CAML over the newer stuff.

Check out Becky’s blog for lots of other great SharePoint tips and tricks, too!

Custom Client-side Calendar Query for Office 365 SharePoint Site Using SPServices jQuery Library

I’m building an Office 365/SharePoint Online intranet site for a client and they wanted to show a list of the current day’s events from various calendars on the site, in a format like this:

8:30​ a.m. ​Staff Meeting ​Room 103
​10:00 a.m. Training ​Cafeteria
​3:30 p.m. Retirement Party ​Conference Room

As you might know, you can’t use a normal CAML query to retrieve calendar entries if you want to retrieve reoccurring events that happen within a given timeframe. (If the first instance of a reoccurring event happened outside the timeframe you queried, the event would not be retrieved, even if it had reoccurring events that happened during the queried timeframe.) The Content Query Web Part will not do the trick.

On projects past, I’ve simply created a web part with a custom CAML query that utilizes the DateRangesOverlap node, and installed that web part using a solution package. This being Office 365, that’s not an option. I could have created a sandbox solution containing the web part but that’s also not a preferred approach since Microsoft seems to be deprecating sandbox solutions. At the urging of Marc Anderson, I tried using his SPServices library.

The SPServices library is a jQuery library that accesses SharePoint web services. By attaching your library to a particular Office 365 SharePoint URL, you can retrieve list items using the SharePoint web service, then use them with jQuery. There’s a discussion thread [on the SPServices Codeplex site – lots of other great stuff there, too!] about how to use SPServices to retrieve calendar entries. I decided to modify the file provided in that thread and use it. The main modification I needed was the ability to combine calendar entries from more than one calendar and show them in a common calendar. This meant utilizing a sorting function after entries from multiple calendars were retrieved so all entries would be listed in the proper order.

You can download my calendar.js file here.

Once I had added the script to my site, I added the following lines of code to my page layout in the header:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.3/jquery-ui.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/0.7.2/jquery.SPServices-0.7.2.min.js"></script>
<script language="javascript" src="/Style Library/Scripts/calendar.js" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function (){
  CallSPServicesCalendar("https://[sitename].com/site1", "Calendar 1");
  CallSPServicesCalendar"https://[sitename].com/site2", "Calendar 2");
  $('div.calendarItem').sortElements(sortByDate);
  if ($('div.calendarItem').length == 0) {
   $("#calendarData").append("There are no events scheduled for today.");
  }
 });
</script>

The script block at the bottom passes in the URL of the web being queried as a first parameter, and then the name of the calendar list as a second parameter. CallSPServicesCalendar is the name of my function in calendar.js that retrieves calendar entries. At the bottom of my calendar.js I have a function that sorts the calendar entries, which you can see is being called with .sortElements in the script above. If no list items are retrieved, a message is displayed saying there are no events. If you want to query more calendars, simply add new calls to the CallSPServicesCalendar function.

In the calendar.js file you’ll notice a section with Field nodes that get passed into the CAML query. You can modify this section to add your own fields if you have custom fields you want to retrieve and display.

In the body of the page, I added a div tag like this, and this is where the event information was added in the page:

<div id="calendarData"></div>

In the calendar.js file, you can modify the HTML that gets rendered for each calendar entry.

Rolling Up Content in SharePoint Using the Data View Web Part (DVWP)

In a recent post, I pointed out a way to roll up calendar entries using the Data View Web Part (DVWP).  That approach works if you have a fixed set of calendars for which you’d like to display the roll-up.  But what if you’d like the roll-up to be dynamic, i.e., have it display events for any new calendars that are created below a certain place in your site hierarchy?

Well, the way to do this is still using the trusty old DVWP (how could we live without it?!?!?!).  There are several DataSourceModes that are available in the DVWP that aren’t exposed in the SharePoint Designer interface.  (ListofLists, Webs, and CrossList modes. ListsofLists and Webs modes show the collection of lists and the collection of subsites for a given site.)  The mode that we need here is CrossList, which allows us to display items across lists below a certain point in the site hierarchy.

Here are the basic steps:

  • Set up your DVWP so that it has the display that you want for all of the lists, but do it the way you normally would for a single list. (i.e., pick one of your lists and make everything pretty for it alone.)
  • Now, if you aren’t already there, switch to code view, and in the code for your DVWP find the DataSourceMode property and change it from List to CrossList.
  • Right after that property, you’ll see the SelectCommand property.  This is the code that tells the DVWP what query to use for the SPDataSource.  Add <Webs Scope=’Recursive’></Webs> immediately after the opening quote, and leave the rest of the SelectCommand as it is.
  • Immediately after this section, you will see values for <SelectParameters>, <DeleteParameters>, <UpdateParameters>, and <InsertParameters>.  You can delete all of these, as they are not relevant to the CrossList mode.
  • Down a little further, you’ll see the <ParameterBindings> section.  Make sure that the line <ParameterBinding Name=”WebURL” Location=”None” DefaultValue=”/sitename/subsitename/”/> reflects the “root” from which you’d like the rollup to work.  (i.e., the DVWP will shown all items from this site and below — That’s what the Recursive scope you put into the SelectCommand does.)
  • Lastly, go a little further down and make sure that the path in the line <xsl:param name=”WebURL”>/sitename/subsitename/</xsl:param> matches the one above.
  • You can also remove any references to ListIDs, as they aren’t relevant.

If you’ve done everything right, you should see items returned by the DVWP that come from all of the like-structured lists below the site you’ve indicated.  You can continue to make formatting changes in the XSL, but to me it seems easier to get it at least close to right before you switch to CrossList mode.

NOTE: I posted an update to this post on September 21, 2008.  You should read that followup in conjunction with this post.