SharePoint 2013 JSOM and Social API
The SharePoint team at Microsoft has done a great job preparing for the launch of SharePoint 2013. The number of developer samples, video, and blog post has been a tremendous help getting ready for the changes to the platform. While preparing for my session at the SharePoint Conference 2012 (#SPC12) I found the code samples to be very helpful for presenting the basics of how the access and use the social API. For example, the article How to: Read and write to the social feed by using the JavaScript object model in SharePoint 2013 has several tricks for working with the JavaScript Object Model (JSOM) in SharePoint 2013. With this as our starting point, I decided to try to incorporate the Personal Feed into the new People search results. Here is the result that I am building. All of the code is contained in the Hover Panel, you can download it here. As I write this post I realize there are a LOT of dependent technologies in play. For example, the people you seek must have My Sites in order to participate in 2013 Social, this is a new requirement based on the new storage model. Also, adding display templates to Search is a whole topic on it’s own, I’ll cover that briefly in this post and in detail in a follow-up post. Anyway, here is the finished product from this demo.
Calling Social with JOSM is done just like it is with other JSOM functions with a few new Social objects thrown in for added functionality:
The code samples that follow highlight the important sections of code. The samples are not complete. For the complete code sample download the code and review it.
As it turns out, this was one of the most problematic sections. I had trouble getting the timing right in the search page to be certain that the ClientContext would load correctly. Here I demonstrate how I get the client context. Below, in Search Tricks, I demonstrate how to get the timing right and ensure that you are calling your function after all the JavaScript has loaded. This code snippet also demonstrates how I have been debugging my HoverPanel. Using IE and the Developer Tools, you can write to the Script debugger panel with the console.log method. This enables your code to run at full speed while debugging without getting in the way of the hover behavior.
// Initialize the current client context and the SocialFeedManager instance.
try
{
console.log("Get Client Context...");
clientContext = SP.ClientContext.get_current();
}
catch(err)
{
console.log(err.message);
return;
}
This is what the debugger looks like after a few successful runs:
Create the FeedManager by passing the ClientContext to the constructor of the SocialFeedManager. Then, optionally, set the necessary options for the results. In this case I only want 5 threads, but I could also change the sort order and other options.
feedManager = new SP.Social.SocialFeedManager(clientContext);
// Set parameters for the feed content that you want to retrieve.
var feedOptions = new SP.Social.SocialFeedOptions();
feedOptions.set_maxThreadCount(5); // default is 20
You have a choice of the feeds for the FeedManager to return. In this sample I am interested in the Users feed (or timeline or whatever you call it today.) So I’ll use the getFeedFor method and pass a username. (I get the user name from the Search Result, more on this later.) If I wanted the logged in users Personal Feed I would use getFeed and pass SP.Social.SocialFeedType.personal, for News pass SP.Social.SocialFeedType.news and timeline takes SP.Social.SocialFeedType.timeline.
targetUserFeed = feedManager.getFeedFor(targetUser, feedOptions);
The last step is to load the ClientContext and then execute the query. The query function takes a success and failure callback. If successful we can write the results to the UI, if fail you can write the error (or handle it some other way) or just pass null and ignore the error.
clientContext.load(feedManager);
clientContext.executeQueryAsync(CallIterateFunctionForFeeds, RequestFailed);
There are many new features in Search for SharePoint 2013. I plan to write a couple articles about how to create cool new search visualizations using Display Templates, but for now I’ll show you a quick way to add your code to the People Search Result template.
var hoverUrl = "~sitecollection/\_catalogs/masterpage/Display Templates/Search/Item\_Person_HoverPanel.js";
var hoverUrl = "~sitecollection/\_catalogs/masterpage/Display Templates/Search/Item\_Person\_Social\_HoverPanel.js";
if ($isEmptyString(uname)) { uname = ctx.CurrentItem.YomiDisplayName }
<li>
<div class="ms-srch-hover-subTitle"><h3 class="ms-soften">SPC Social Feed</h3></div>
<table width="100%" id="_#= socialId =#_"></table><br/>
<span id="spanMessage_#= socialId =#_" style="color: #FF0000;"></span>
</li>
//SPC: Post Render Callback
AddPostRenderCallback(ctx, function(){
console.log("Post render callback: " + ctx.CurrentItem.AccountName + "(" + socialId + ")");
SP.SOD.executeFunc('sp.js', 'SP.ClientContext',function()
{
console.log("Calling GetFeeds in execFunc...");
GetFeeds(ctx.CurrentItem.AccountName, true );
});
});
As I worked through this demo I found that many of the challenges were caused by the new Search page loading procedure. You have to be certain that your code runs after the page is finished loading. I also needed to target specific di tags on the result page. I used another trick to ensure that I had unique IDs on the page. I solved these two challenges as follows.
If your scripts fail to load correctly you will get the dreaded “Unable to get Client Context” or you will simply have a null ClientContext to deal with. I found that, for a while, my script worked fine, then, later for no apparent reason, they did not. Some process changed the timing and now my script was failing. In order to force SharePoint to ensure that my script loaded correctly I found that I had to call SP.SOD.executeFunc. You may be familiar with executeOrDelayUntilScriptLoaded, I was, but I found that it would randomly fail and not throw an error. I found executeFunc to be the most reliable function for this purpose. So, in the end, I wrapped my GetFeeds function with the executeFunc to ensure that I would always get a ClientContext.
If you look at the Table that I created in the display template above, I used a substitution tag for the page of socialId. The “_#=” markup is used by the Display Template to perform replacements when the page is running. (I really need to write a post about this…). The cool thing is it will replace any page variable. In my case I needed to uniquely identify the tables for the social data I was returning. All I had to do was create a variable and then reference it in my code. I create the variable like this:
var socialId = encodedId + "_hoverSocial";
Which appends “_hoverSocial” to the unique encoded ID of the result that was hovered over. Now I have a variable for my JQuery to reference the right instance of the table for my Social Results.
In my scenario I wanted the User Name of the person I am looking at in the Search Results page. Since this is a People Search Result I have access to the Managed Property “AccountName” that is associated with the context of the CurrentItem. (OK, I seriously need to write up another post to make this more clear.) Any way, if you look at the method where I am calling GetFeeds, I pass in the {%%} as ctx.CurrentItem.AccountName.
One of the trickier parts of making this work has nothing to do with development. I simply needed to change the behavior of People Search so that SharePoint would load my result types rather than the defaults. Here are the steps to make that happen. Note, you have to have already added the Item_Person_Social and Item_Person_Social_HoverPanel HTML files before you attempt this action. They need to be present to get the wire-up to work.
The final results are simple but they show how powerful this new version of SharePoint is for developers. We are able to implement a cool addition to search using the out of the box APIs and without deploying code to the server (beyond the JavaScript that we just waded through).
Ready to start your next project with us? That’s great! Give us a call or send us an email and we will get back to you as soon as possible!
+1.512.539.0322