SharePoint Calendar: Managing Exceptions in a Recurring Event Schedule

The object returned by the SharePoint JavaScript CSOM for a recurring event schedule is very intuitive. For example, an event which occurs every day for the next year (up until 2017-02-21) reads as follows in the RecurrenceData field of the SP.ListItem.fieldValuesAsText property:

RecurrenceData: "<recurrence><rule><firstDayOfWeek>su</firstDayOfWeek><repeat><daily dayFrequency="1" /></repeat><windowEnd>2017-02-21T01:00:00Z</windowEnd></rule></recurrence>"

I used something similar to the above schedule to start a daily timecard entry event in a SharePoint Calendar. The scenario is basically to track a daily task to submit a timecard, but there are a lot of exceptions. Take for example an employee named Karen. She has alternating Monday-Tuesday and then Thursday-Friday off and works weekends. Bob happens to be putting in a bit of overtime for the next week before going on vacation. Again, exceptions occur often, so we see variable schedules for Karen and Bob:

SharePoint Calendar
Schedules for Karen and Bob.

If we were to process the RecurrenceData XML rule above in order to build logic which triggers an e-mail or reminder to Bob/Karen to enter their timecard, we’d end up triggering the activity on dates when they were off (days like the exceptions above, holidays, sick days, and so on). Fortunately, the exceptions are also stored as list items in the SharePoint Calendar list item collection – they’re just not shown on the calendar view. In the above Calendar, we’ll get back 6 list items: the recurring event schedule for Karen, the recurring event schedule for Bob, and then the four exceptions to Karen’s schedule.

Calendar Objects in Debugger.
Calendar Objects in Debugger.

The first thing to do is to group the exceptions with their parent event. As noted, this is very intuitive:

  1. Group the list items on the UID property or match them by the MasterSeriesItemID property
  2. Then, sort the items in ascending order by the Order property or ID property
  3. There are even more creative ways to match and order and identify the exceptions you want to work with. See below for examples of use fields…SharePoint even prepends “Deleted: ” to the Title property of the exception

Finally, you can now use the EventDate or RecurrenceID property to identify the exact date of the exception to the schedule and prevent the e-mail or reminder from going out.

Useful Exception Item Properties
Useful Exception Item Properties

SharePoint – Term Store Custom Sort Order in JavaScript

Terms in the SharePoint Managed Metadata Term Store can be ordered through the Custom Sort Order option in the Custom Sort tab of the Term Store Management UI:

Custom Sort in the Term Store management UI.
Custom Sort in the Term Store management UI.

However, if you pull items from the term store using JavaScript getAllTerms, those terms will be returned alphabetically, not in the custom sort order. That is, a call to…

var terms = termSet.getAllTerms();

…will not maintain ordering you’ve specified with the Custom Sort Order by default. What you should do is include the ‘CustomSortOrder’ field in your load before you execute the query. This looks as follows:

var terms = termSet.getAllTerms();
context.load(terms, 'Include(...,CustomSortOrder, ...)'); // specify list of all required fields
context.executeQueryAsync(function () {
    var termEnumerator = terms.getEnumerator();
    while (termEnumerator.moveNext()) {
        var currentTerm = termEnumerator.get_current();
        var termOrder = currentTerm.get_customSortOrder(); // Include enables this to be called
        ...
        ...
    }
},...);

If a custom order is present, the variable termOrder (i.e. var termOrder in the above example) will include a colon delimited list of the term store item Guids that are children of the current term. This delimited list will be built in the correct Custom Sort Order specified in the Term Store. You can easily parse and work with this list now to get items from the Term Store in the correct Custom Sort Order:

var orders = termOrder.split(':');
for (var i = 0; i < orders.length; i++) {
    var key = orders[i]; // key is the term Guid
    // do something, you're looping through children in the correct Custom Sort Order
}

That’s all there is to it:

  1. getAllTerms
  2. Provide your Include fields. At the very least for this blog, include CustomSortOrder
  3. Now when you execute the query, the fields you specified will be available in the return objects
  4. Call get_customSortOrder() to pull the field
  5. Split on the delimiter (i.e. ‘:’) and go

SharePoint 2013 Installed App Properties

This is a quick SharePoint 2013 developer post which highlights how to get properties of your installed apps on a given web.

The first step is to obtain the App Instance Id. You can do this by navigating to the site on which the app of interest is installed, hovering over its link in the Current Navigation area or Site Contents area, and observing the URL.

InstanceIdUrl

With the ‘instance_id’ value in hand, you can now execute the PowerShell commands:

$web = Get-SPWeb http://sharepoint/full/path/to/installed/site
$web.GetAppInstanceById("<instance_id>")

This will now render the App details:

AppPrincipalId  : <Claims String>
InError         : <True|False>
App             : <App Class>
SiteId          : <Site GUID>
WebId           : <Web GUID>
Title           : <App Title>
Id              : <Instance_ID>
LaunchUrl       : <Relative Url>
Status          : <Installed|Other>
RemoteAppUrl    : <Remote Web Url>
AppWebFullUrl   : <Full Launch Url For App>
SettingsPageUrl : <App Settings Page Url>

In development what I find most useful are the RemoteAppUrl and the AppWebFullUrl properties. These can be used to setup DNS and browser favorites on the various machines in your test environment to enable you to test non-public URLs in a small lab environment (e.g. one without a proper DNS server).

Quick Tip: jQuery UI and Moment.js

This is a quick post about using jQuery UI and Moment.js to render calendar UI within, for this case, SharePoint.

When using the CSOM, SharePoint will return DateOnly fields where the date value will likely need to be parsed in some way before you render the value for users.  For example, today, 7/22/2015, will be returned as Wed Jul 22 00:00:00 PDT 2015. At the very least, you’ll likely want to split and rejoin (substring, etc.) the date to exclude the “00:00:00” time stamp before rendering it in any way considered to be “friendly”.

Now, if you use a simple calendar control from jQuery UI, you’ll want to take the parsing a bit further, and you’ll also need to convert something like the stamp above to read “7/22/2015”. Otherwise, by default, the date won’t mean anything to the jQuery UI calendar if you’ve casted a control using the datepicker() method.

You can imagine the HTML/jQuery:

$('#new-task-startdate').datepicker();
...
...
<input type="text" id="new-task-startdate"/>

So, how do we convert “Wed Jul 22 00:00:00 PDT 2015” to “7/22/2015”. Well, you could use a few one-off JavaScript date/time objects and string manipulation if you’re going to do simple reformatting like this a few times. But, as things get more advanced and heavy date manipulation is required, I prefer to use the the moment.js libraries. I find moment.js extremely intuitive, and more importantly, it scales up to do hundreds of alternative formats and when you really want to get advanced and work with timezones, there with moment-timezone. It’s a library worth learning for its ease of use, dozens of formatting options, and solid timezone support. So, how much code is needed to get “Wed Jul 22 00:00:00 PDT 2015” converted to “7/22/2015”? One line:

var startDate = moment(spStartDate).format("MM/DD/YYYY");

And, to the point above, if you expect to cast dates back and forth between UTC and the local zone, or you need to render the local time according to city and country names, you’d have that added support with just a few more lines of code.

Ajax – Don’t Forget the Basics (or go learn them)

During interviews, I often ask candidates how to “manually” implement an Ajax call in classic JavaScript. I’m not asking for the exact perfect syntax off of the top of their heads, however, I do want to hear about the basic core/native classes, objects, properties, and methods that enable asynchronous request/response handling.

Many developers only know the jQuery shorthand syntax (i.e. $.ajax and friends), and many know neither implementation (native nor jQuery) at all. For the former, I usually take jQuery away as an option and then commonly discover that fundamental knowledge of native JavaScript is poor, and really to the point of the question, that a solid understanding of asynchronous message processing is lacking.

Hopefully this post gives the reader some insight on objects and concepts that s/he should know well if s/he wants a deeper understanding of asynchronous request processing in HTTP through JavaScript.

So, what native classes, objects, and properties I’m referring to:

  • XMLHttpRequest
  • Msxml2.XMLHTTP
  • Microsoft.XMLHTTP
  • onreadystatechange property of these objects
  • open and send methods of these objects
  • readyState and status properties of these objects
  • responseText and responseXML properties of these objects

And, what should one generally know at a minimum

  • How to get the correct XMLHTTP request object based on the browser’s JavaScript and ActiveX support
  • How to assign an event handler to the onreadystatechange property
  • How to open and send requests along with POST versus GET
  • setRequestHeader, common Content-Types, and what each content type generally means
  • How to send parameters in the request
  • How to process requests’ results in the onreadystatechange handler
    • What the various readyState values are and what they mean
    • What some common success and failure values are for the status property
    • What responseText and responseXML are all about

Of course, there are many web based and bound tutorials on this topic; read through them and determine which is most effective and follows safest/best practices. Me, personally, I learned my basic implementation from a book titled, “Bulletproof Ajax” by Jeremy Keith many years ago and have continued to build on those concepts ever since.

Monetizing SharePoint and Office Apps

Monetizing an app involves specifying the billing model, how to go from user to site pricing, as well as other options around trials and so forth. These are common things one expects to consider when looking at selling apps in a market place.

When it comes to SharePoint and Office apps, I found some clear documentation explaining their market’s options around these kinds of monetization settings. Take 5 minutes to read the following article and you’ll likely have a majority of your questions answered on setting a pricing model and monetizing your apps in the SharePoint and Office app market place: http://tinyurl.com/p2ccj9v

SharePoint Hosted App Quick Update

During the development and testing phase of a SharePoint 2013 Hosted App, the information I was reading described the app update process in a way which had left me:

  • A bit uncertain if I needed to use Visual Studio to complete the upgrade
  • Fairly certain that I needed to either wait 24 hours or execute a command in the SharePoint Management Shell, as described in the App for SharePoint update process article, in order to for the upgraded app to become available.
    • Note: I’m working in O365, so I can’t run timer jobs and that means I’d still need to wait for Internal App State Update to execute
    • Even when we can force the timer job to run, we’re now taking several heavy steps just to update our app

It turns out that one doesn’t need Visual Studio nor must one wait and/or execute the Set-SPInternalAppStateUpdateInterval command and/or force Internal App State Update to run. We can accomplish everything in the browser.

Let’s assume that you’re working in the “Napa” Office 365 Development Tools environment, you’ve published a new update of your app with the version revised, and you’ve uploaded that version to the App Catalog. Now, you go to your staging site, but you likely won’t see the “An update for this app is available” text in ‘Site Contents’ listing for your app. What you can do then is, click the ellipsis, and select ‘Details’:

App Upgrade Details

You’ll be redirected to the App Details page, and when loaded, click the “App Profile” link:

AppUpgradeProfile

And, from here, the UI to complete the upgrade is pretty self explanatory.

App Upgrade Get App

Development Environment Tips for Napa

As browser based IDEs and page designers continue to become commonplace, our demand on them to reach parity with their client based counterparts is to be expected. The capabilities and features of a development environment greatly impact accuracy (think Intellisense), readability, writeability, and the overall time and effort it will take to test and maintain our software. Working in the browser doesn’t require a degraded core experience, and the Microsoft “Napa” Office 365 Development Tools experience is proof of that.

Along the many great features and options, here are a couple that I find very useful as well as pointers to the rest.

Split Screen

When developing, we often find ourselves viewing source files side-by-side to trace program flow, view sample data, read APIs, and so on. The Visual Studio client provides the capability to split a single window pane for these common tasks, and so does “Napa”. The button to launch split screen is in the upper right hand corner of the source code editor. This control is outlined in red below.

Before…

Napa Split

After…

Powerful Search

Developers need the capability to search all source in a solution and we often find ourselves refactoring code through search-and-replace. Napa provides some pretty powerful search capabilities to achieve these common tasks and much more.

Searching Specific or All Files…

When using the Search task pane exhibited below, you’ll see that you can specify file name query parameters as well as regular expressions to filter your results. After searching, the pane provides intuitive arrow icons through which search results can be expanded and selected (causing the results to be loaded in the source edit pane).

Napa Search All

Search and Replace…

Getting to Search and Replace in Napa is identical to the steps taken for Visual Studio.

  1. Ctrl + F and use the drop down in quick find
  2. Ctrl + H will launch quick find with ‘Replace’ already open

Search and Replace

And More

The commands above offer just a glimpse of the powerful set of pro-dev features offered by Napa. Explore the rich feature set further by listing all or editor-only options via the ellipsis UI in the main control pane or in the editor pane.

Command Dialogs…

Napa Commands

Open in Visual Studio…

Finally, the Visual Studio client is seamlessly integrated. So when you do need to upgrade your development experience to support project integration, test automation, or the addition of managed code…just click the Open in Visual Studio button.

Open in Visual Studio
Open in Visual Studio