SPServices Stories #11 – Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm

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

Introduction

I ran across this SPServices Story in a post on the blog at CTS. The author of the post, Matt Ingle, is a Senior Consultant at CTS in Birmingham, AL. According to Matt, he is a team lead for a group called the SharePoint Factory. The SharePoint Factory team roles correspond to the various areas of the SharePoint family of products. This role-based approach allows for technical depth and specialization within the SharePoint functional areas.

SPServices has a function called SPRedirectWithID, but it’s problematic in SharePoint 2010 due to the dialogs that SharePoint uses to show the list forms. You can ensure that the function works just fine by turning off the dialogs, but that’s not always desirable. I’d turn them all off if I had my druthers because most list forms require more screen real estate than the dialogs provide without a lot of scrolling. They also don’t obviate the need for a ca-chunk postback when you save the item.

Given this state of things, Matt came up with a way to accomplish a similar thing in a different way. Here’s Matt’s take on the task. It’s a nice way to go if your information architecture is very clear and you know that your forms won’t change much, if at all, since Matt is bypassing the simple NewForm we get for “free” from SharePoint. On the other hand, this type of approach may become more common as we move forward with SharePoint and HTML5 compatibility.

Using SPServices and jQuery to Perform a Redirect from a SharePoint List NewForm to EditForm

By Matt IngleMatt Ingle

Problem: In SP 2010, you have a parent list and multiple child lists connected through Lookup columns. You have created the custom Display and Edit forms for the parent list containing XsltListView web parts for the child lists filtered through query string view parameters. Refer to this article for more information on this solution.

Now you need a way to redirect the user from the NewForm to the EditForm after saving the parent list item while passing the newly created item ID as a query string parameter. The problem is there is no way to do this out-of-the-box (OOB).

Solution: You can use jQuery and the SPServices library from CodePlex to utilize SharePoint’s Web Services. The two operations I will use in the following example are GetUserInfo and UpdateListItems.

Note: Be sure to read the IMPORTANT NOTES on the SPServices Home page about supported versions. This example will use the (“[nodeName=’z:row’]“) syntax which no longer works with jQuery 1.7. I will be using jQuery 1.6.2 and SPServices 0.6.2 in my example. However, if you want to use 1.7, an alternative solution to using this syntax can be found here by Steve Workman. [ed: Use the SPFilterNode function, which will work with any version of jQuery: .SPFilterNode("z:row") and ensures cross-browser compatibility.]

By using the SPServices operation to create the new list item you will be bypassing the OOB Save process for the SharePoint list form. This means that you will lose the validation on the form and will need to create your own validation logic using jQuery. In the following example I will be implementing the required field validation for my list fields.

Example: At this point you should already have a custom NewForm for your parent list.

Below each field to be displayed on the form, add some text wrapped in a <span> tag with unique ids that will be used to display our custom validation message. I worded mine the same as the text displayed by SharePoint. Notice my id for the <span> tag below is ‘valBU’. We will use jQuery later to select this element by the id.

clip_image0024

Additionally, we will need to add a custom button to our form in place of the OOB Save button. This will allow us to attach our custom code to the Save button’s click event.

clip_image004

Next, add a Content Editor WebPart (CEWP) directly below the DataFormWebPart. This will hold our jQuery/SPServices script.

In the CEWP, add the script references to the jQuery and SPServices libraries. I uploaded mine in a new ‘Scripts’ folder stored in the ‘Style Library’ folder so that it is accessible to other pages in the site as needed.

To begin the script, add code to hide the text containing our custom validation messages. Place this code in the $(document).ready function. Next, add a line to attach the method CreateNewItem to the Save button’s click event.

clip_image006

Next, we can implement our custom validation logic. The following method will be called in our CreateNewItem method to validate our form before creating the new item. It starts by using jQuery selectors to obtain the values of the list fields on the form. We can use the ‘title’ attribute for the selectors which contains the name of the list field. In my example, I have 2 drop-down list boxes so I am looking for select elements. For a normal text field you would look for input elements.

For a PeoplePicker, the selector used is a little different. There are different ways to obtain this value, but for our purposes (looking for a single PeoplePicker on the page) you can just look for a textarea element with the title ‘People Picker’. If you have multiple PeoplePickers on the form then you would need to research a way to be more selective. [ed: You can use the SPFindPeoplePicker function in SPServices for this.]

When you have an empty PeoplePicker value you will get ’&#160;’ which is the HTML code for a non-breaking space. Simply check for this value versus an empty string as done for the other fields.

This method counts the number of empty fields and toggles display of the custom validation messages. If there are no empty required fields then it returns true, false otherwise.

clip_image008

Now we can implement the CreateNewItem method. First, use jQuery to select the form fields and obtain the values.

Again, we need to do something different for the PeoplePicker. The value of the PeoplePicker contains a lot of stuff we don’t really need so we have to parse through it to find the user login name.

With this value stored in the ‘buFinContollerPerson’ variable, we will supply it to the ‘userLoginName’ parameter for the GetUserInfo operation. This will be a value like ‘EXT\mingle’.

We are calling the GetUserInfo operation in order to get the correct format needed to save the PeoplePicker value to the list. This format is ’37;#Matt Ingle’ (<UserID>;#<UserName>).

clip_image010

To complete the CreateNewItem method we will call the UpdateListItems method. To specify the creation of a new list item you need to specify “New” for the batchCmd parameter. In addition, supply the list display name (one shown in UI) for the listName parameter. The values to be submitted for the new list item are specified as value pairs in the valuepairs parameter.

Note:We are supplying the fullUserName obtained from the GetUserInfo operation as the value for the PeoplePicker field BUFinContollerPerson.

Once the operation has completed we will parse the XML response to find the newly created item ID. This is where we use the (“[nodeName=’z:row’]“) syntax. This value is supplied for the ID query string parameter to redirect the user to the EditForm.

Also notice the <div> tag below the <script> tag. This is where you can specify the location of the debug output for the SPServices operations. Simply uncomment the calls to SPDebugXMLHttpResult to see the operation results displayed. Be sure to comment out the redirect though when debugging, otherwise you will not stay on the page to see the results. :-)

clip_image012

Advertisements

SPServices Stories #12 – SharePoint and jQuery SPServices in Education: A Case Study

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

Introduction

Ben Tedder (@bentedder) has long been a fan of SPServices and his writing about it is great, to boot. I liked this post back when Ben first put it up on his blog because it really does tell a story, and SPServices plays a significant role in it.

Ben has built quite a few real-world solutions using SPServices that transcend what SharePoint can do. By using SharePoint as the back end data repository, Ben has managed to create solutions that provide a great user experience and are far more efficient than SharePoint can be when building through the UI. He does this without deploying any server-side code, just as I always aspire to do. Great solutions with minimal footprints.

Thanks to Ben for letting me republish this post from his blog.

SharePoint and jQuery SPServices in Education: A Case Study

24 Sep 2012

bentedder-profile

This is a morphed, updated, renewed version of the SharePoint Scheduling Assistant. I’m not releasing this version quite yet, but this is a brief case study on how it’s working at a specific school.

Business Needs

The International School of Beijing needed a way for Elementary School parents to book time slots with teachers during bi-annual parent-teacher conferences.

The requirements:

  • Easy to use (training is impossible).
  • Integrate into the current intranet portal.
  • Sync with the database to omit any kind of manual setup for secretaries.
  • Deny parents the ability to book more than one slot with the same teacher.
  • Allow parents to book the same slot for two different teachers (in case mother and father come in and meet with 1 teacher each to save time)
  • If two or more parents are online at the same time, correctly queue the submissions so a double booking does not occur.
  • Allow teachers to pre-block out slots where parents cannot book times.
  • Allow teachers the ability to see their entire schedule, including which student is coming in during which time slot.

Solution (SharePoint, jQuery, and SPServices)

A SharePoint solution was built with jQuery to meet the requirements of the Elementary School. Let’s break down how the solution was created:

Part 1 – SharePoint

Within SharePoint three lists were created:

  • Bookings (Each reservation had its own row in this list that stored the details of who booked it, for which teacher, etc.)
  • Time Slots (A pre-determined list of time slots…in this case a list item was created for each 20 minute time slot from 12-6pm on Thursday and Friday Oct 18 and 19).
  • People (An external content type that pulled records from the database for each student, each of their parents, and each of their teacher names)

One of the trickier parts of this solution was grabbing the external content from the database in a usable way. Once it was in, we were able to work with the data. However, this list has 10,000+ items, so dealing with larger data like this was quite challenging. Enter jQuery.

Part 2 – jQuery and SPServices

The bulk of this solution was created with the jQuery and jQuery SPServices Libraries. Using jQuery, we stepped through the process like this:

  1. Get the details of the logged in user (parent) using SPServices
  2. Hit the SharePoint external data list once, filter it by Parent (matching to the Parent login ID), and store it in a javascript object for later use. This was the biggest strain on the system. We minimized the data call to only one time, but even still, pulling a list of 10,000 records even once isn’t super quick.
  3. Get all the children of the logged in parent, push them to a drop-down menu
  4. Get all the teachers of the selected child from #3, push them to another drop-down menu
  5. Get all time slots from the Time Slots list, push to a third drop-down menu
  6. Retroactively disable all time slot options that have already been booked (by searching through the Bookings list for records that match the time slot and the selected teacher)

Once the data was present, the parent could interact with it in two ways, book, and delete.

To book a time slot, the selected child, selected teacher, and selected time slot (along with a comments area) was submitted and saved to the list. To delete a time slot, a delete button is appended to each reservation in the on-screen schedule with the ID of the reservation as the ID of the link element.

The data from the Bookings list is checked once during the time slot selection process, and again during the form submit process to make sure no double bookings have occurred.

Benefits

This solution enables, for the first time at this school, parents to go online and manage their entire Parent-Teacher Conference schedule. Also, as an added bonus, if a mother and father both login, they can see the complete schedule for their child, even if only one of the parents made the bookings.

Once a parent books a time slot, they receive an email containing the details of their reservation.

An additional feature of this solution was that it was duplicated and tweaked for teachers to use a similar interface to pre-block out time slots where they did not want parents to come (ie, lunch, coffee break, going home). In that scenario the “one-block” restriction was removed for teachers, allowing them to customize when parents would be given the option to come in.

SPServices Stories #13: Durandal SP3: Developing SharePoint SPAs Made Easy

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

Introduction

Rainer Wittman (@RainerAtSpirit) and I have been emailing back and forth for a few weeks now. He’s been trying out the new alpha of SPServices 2013.01 which includes jQuery promises aka Deferred objects capabilities (soon to be a real release, I promise!) with the Durandal JavaScript framework. Durandal is a framework for building SPAs, or Single Page Applications.

This is something that SharePoint 2013 does to some degree with the Minimal Download Strategy (MDS). If you’re interested in how MDS works, here are some posts that go into more detail about it:

Those of you who are purists will tell me that I’m comparing apples and oranges, and that’s sort of true. However, the goals are similar: send as little of the page transitions down the wire as possible to make those transitions as fluid and responsive as possible. We see this sort of approach more and more, especially in mobile interfaces.

I’ve done SPA-like things even with SharePoint 2007 using AJAX. By maintaining the overall chrome of the page (top nav, Quick Launch, footer) as a constant, we can do something as simple as AJAXing in a new copy of the same page, parsing out the main panel, and replacing it in the user’s current copy of the page in the DOM. You also see this in SharePoint 2010 with the asynchronous refresh capability available with some Web Parts (See: Asynchronous
Update in SharePoint 2010
from @wonderlaura).

If you haven’t heard of Durandal (I hadn’t), here’s some information swiped from the Durandal home page:

Comfortable

We didn’t try to re-invent the wheel. Durandal is built on libs you know and love like jQuery, Knockout and RequireJS. There’s little to learn and building apps feels comfortable and familiar. Dive in and enjoy.

Feature-rich

MVC? MVP? MVVM? Yes. Messaging, navigation, modals? Check. Durandal has the features you need to build whatever apps you can imagine; the apps of today and of tomorrow. Let your creativity soar.

Versatile

Building an Android phone app? An enterprise LOB targeted at Windows? A web gaming platform? No matter how large or small the app, it’s effortless with Durandal….and we give you the tools to develop on any platform, for any platform.

I expect we’ll hear more from Rainer about this cool way of building SharePoint interfaces. As you read through his post below, you’ll probably be very impressed to see that his approach works for SharePoint 2007, 2010, or 2013. If you’re still on 2007 and woulds like to make your installation fell a heck of a lot more “modern”, this is an approach that has legs going forward. You’ll also see some links in his post to live, working demo pages so that you can get a feel for what he is driving at.

This article was originally posted on Rainer’s blog at Durandal SP3: Developing SharePoint SPAs made easy.

Durandal SP3: Developing SharePoint SPAs Made Easy

Hi there,

In the last post I introduced you to Durandal a SPA Framework, which can be used to create SPAs on top of the SharePoint infrastructure. This time we’re going to leverage Marc Anderson’s SPServices as a data service for our SPA.

The obvious advantage is that web services are around for a long time, so one SPA (same code base) runs in SharePoint (2003), 2007, 2010 and 2013.

The obvious disadvantage is that web services are deprecated in 2013, so they might go away with the next major release. If you are already running on 2010/2013 and don’t have to support older browser versions you might want looking into using REST services with JayData or Breeze instead… but that’s worth another story.

Seeing is believing so here a couple of screen shots using IE versions that roughly matches the SP release time.

SharePoint 2013 | IE 10: 2013-04-08-SP2013Demo

SharePoint 2010 | IE 8:

2013-04-08-SP2010Demo

SharePoint 2007 | IE 7:

In SP2007 you’ll notice some issues with the CSS that is used in the SPA otherwise it’s fully functional. That is less an issue with IE7, but more with SP2007 that is running pages in Quirks mode. A quick workaround would be to apply a DOCTYPE to the pages that host your SPA.

2013-04-08-SP2007Demo

SharePoint 2003 | IE 6:

Sorry, I’m out of historic SharePoint VMs. Please give me a shot if somebody has still access to a SP2003 environment. I’d love to add the missing screen shot.

Now, after hopefully getting you excited, here’s the bad news. The demo is using the alpha release 2013.01ALPHA5 of SPServices, so I won’t make the demo code available through Github as usual. I’ll update this post once the next official version of SPServices has been released and tested with Durandal SP3.

The good news is that there are two public available pages that allows you to go hands-on. Both are best viewed with your favorite console open.

  1. development version:
  2. optimized build:

Without going into the details let see what the Promises demo app is doing when you activate the list route (/#lists).

  1. Retrieve information about the lists in the current site via SPServices GetListCollection method (with caching)
  2. Retrieve detail information about the selected list via SPServices GetList method and build a mapping that can be used in SPServices SPXmlToJson method (with caching)
  3. Retrieve item information via SPServices GetListItems (NO caching)

Update 2013/04/11: The life demo was updated based on some feedback I got. The list overview now produces a configurable row view of lists with meta information like ItemCount and Last Modified. Step 2 and 3 are performed once you select a list.

By opening up the optimized build and filtering the network tab for XHR you can see the three POST requests to lists.asmx nicely lined up. Once you start selecting other lists, you’ll noticed that the number of XHR requests decrease as more and more cached information becomes available.

2013-04-08-OptimizedBuild

The development version on the other side shows far more details via the console. That allows you to get familiar with Durandal’s application life cycle and to inspect the Json result of some spdata methods.

2013-04-08-Development

After reading so far and hopefully seen the Promises demo in action by yourself, I hope that you share my excitement of the upcoming promise support in SPServices. Once it’s part of an official release SPServices will become a perfect fit for Durandal’s life cycle methods.

SPServices Stories #14: Create a Slide Show in SharePoint 2010 using an Announcements List and SPServices

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

Introduction

It’s been a while since I’ve posted a new SPServices Story. This one was sitting in my draft bucket for way too long, so a big sorry goes out to Trace Armstrong (@TraceBArmstrong).

Trace wrote this post about using SPServices to drive a slideshow using an announcements list as the source. This is the sort of common use case that SPServices often sits behind as part of the underlying plumbing.

If you’re using SharePoint 2013 or Office365 running the 15 wave, you might say that one should use REST instead, and that’s an option of course. The nice thing about using SPServices for stuff like this is that if you are on SharePoint 2007 or 2010 or 2013, the SPServices calls are exactly the same. So in a sense, we’ve got easily upgraded code.

Note: I’ve made a few small changes to Trace’s code. One change was to replace .find(“[nodeName=’z:row’]”) with .SPFilterNode(“z:row”). This is required to make things work with up to date versions of jQuery.

Create a Slide Show in SharePoint 2010 using an Announcements List and SPServices

twitter_trace_thumb1By Trace Armstrong

Recently, I had a client who wanted a different slide show for their SharePoint 2010 intranet home page. The original slide show ran using a custom web part that integrated the Nivo Slider, a jQuery based solution. The solution worked great but the person maintaining the news portion of the slider needed a no-code solution for easier updating.

I searched the Internet for a solution and came across this blog (https://www.nothingbutsharepoint.com/sites/eusp/Pages/Creating-your-own-Content-Slider-for-SharePoint.aspx) by Eric on http://www.nothingbutsharepoint.com. The solution was similar to what I needed but my task also required a place for slideshow images.

The first step was using the Announcements list for the announcements slider. I then created two custom list columns, “Image” and “Body”. The “Image” column is a “Hyperlink or Picture” column type and “Body” is a “multiple lines of text” column type.

Using Eric’s model, I referenced SP Services, jQuery, jShowoff, and set about editing the JavaScript code to pull an image column from the Announcements list.

The revised JavaScript looks like this:

$(document).ready(function () {
  var emptyResults = "<div class='sliderDiv'><p class='announceTitle'>Company Name</p></div>";
  var maxVal = 0;
  var toShow = false;
  var heightTemp = 0;
  $().SPServices({
    operation : "GetListItems",
    async : false,
    listName : "Announcements",
    CAMLViewFields : "<ViewFields><FieldRef Name='Title' /><FieldRef Name='Image' /><FieldRef Name='Body' /><FieldRef Name='Modified' /></ViewFields>",
    CAMLQuery : "<Query><OrderBy><FieldRef Name='Created' /></OrderBy>" + "<Where><Or><Geq><FieldRef Name='Expires' /><Value Type='DateTime'>" + "<Today /></Value></Geq><IsNull><FieldRef Name='Expires' /></IsNull></Or></Where></Query>",

    completefunc : function (xData, Status) {
      var itemCount = $(xData.responseXML).SPFilterNode("rs:data").attr("ItemCount");
      if (itemCount > 0) {
        toShow = true;

        $(xData.responseXML).SPFilterNode("z:row").each(function () {
          var modDate = $(this).attr("ows_Modified");
          modDate = modDate.substr(5, 2) + "/" + modDate.substr(8, 2) + "/" + modDate.substr(0, 4);

          var titleHtml = "<div class='sliderDiv'><p class='announceTitle'>" + $(this).attr("ows_Title") + "</p>";
          var imgBody = "<img class='anImage' src='" + $(this).attr("ows_Image").split(',')[0] + "'></img>";
          var bodyHtml = "<p class='announceBody'>" + $(this).attr("ows_Body") + "</p>";
          var expireHtml = "<p class='announceFooter'>Modified: <span>" + modDate + "</span></p></div>";

          //div announcements is added by jshowoff js.

          $("#announcements").append(titleHtml + imgBody + bodyHtml + expireHtml);

        });

      } else {

        $("#announcements").append(emptyResults);

      }

    } //completefunc

  }); //SPServices

  if (toShow == true) {
    $('.sliderDiv').each(function () {
      heightTemp = $(this).height();
      if (heightTemp > maxVal) {
        maxVal = heightTemp
      };
    });
    $('#announcements').css('min-height', maxVal);
    $('#announcements').jshowoff({
      speed : 12000,
      changeSpeed : 3000,
      controls : true,
      animatePause : false,
      effect : 'fade',
      cssClass : true,
      links : true
    });
  } //if stm
}); //ready

I edited a few syntax issues that were unnecessary to the solution and created/referenced a new variable, “imgBody”. The variable adds the img class “anImage” and retrieves the slide show image from the list column “Image”. One of the problems in the solution was SharePoint adding a comma to the end of the file name. The split property removes the comma and the image displayed as intended on the site.

The solution appears like this on the client’s main page.

Slide-ShowThis solution enabled the company to have a no-code update to their main page news slider using an image library and the Announcements list.

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.