After struggling for some time and a whole lot of googling I was able to make this work as magic (that is with JavaScript/jQuery). Here’s what we’ll need to do:

  • Create a Display Template
  • Add some JavaScript/jQuery

Simple right? Yes, after figuring out how to do it it is…

Display Template

For the display template you’ll have to add two managed properties. We will be needing the List ID and the List Item ID, In my case those properties where already there and mapped (I think they might be by default), but if in your case the managed properties are not created go ahead and create them. Here’s how those properties looked:

Managed Properties
Look at the ListID and ListItemID Managed Properties

So from there you have to add those two properties to the Display Template as follows:

<ManagedPropertyMapping msdt:dt="string">'ListItemID':'ListItemID','ListID':'ListID','Title':'Title','Path':'Path','Description':'Description','EditorOWSUSER':'EditorOWSUSER','LastModifiedTime':'LastModifiedTime','CollapsingStatus':'CollapsingStatus','DocId':'DocId','HitHighlightedSummary':'HitHighlightedSummary','HitHighlightedProperties':'HitHighlightedProperties','FileExtension':'FileExtension','ViewsLifeTime':'ViewsLifeTime','ParentLink':'ParentLink','FileType':'FileType','IsContainer':'IsContainer','SecondaryFileExtension':'SecondaryFileExtension','DisplayAuthor':'DisplayAuthor'</mso:ManagedPropertyMapping>

You could also add the LikesCount property but I would recommend against it if you what the likes to be in real-time and, since you most probably do want them to be in real-time, I recommend retrieving the value from the JS code. After having that let’s leave the Display Template for a second and move on to…

The JavaScript

I’ve made this on a separate JS file which I then added to the Search Results page, but feel free to put the code elsewhere. So the first thing you must be thinking is that we need a function for the click of the like/unlike button, and you are right we will absolutely need that… But how would you know what to do if you don’t have a function that goes and checks if the user had already liked the item? That’s the first thing we will need to do and thankfully Simon Pedersen has a post where he shows a function that does this exact thing so basing myself on that (and yes, at this point I’m wondering if I’m a programmer or just a good googler) I built the following function:

function getUserLikedPage(listID, itemID) {
var didUserLiked = false;
var context = new SP.ClientContext(_spPageContextInfo.webServerRelativeUrl);
var list = context.get_web().get_lists().getById(listID);
var item = list.getItemById(itemID);
var likes, success = false;
context.load(item, "LikedBy", "ID", "LikesCount");
context.executeQueryAsync(Function.createDelegate(this, function (success) {
// Check if the user id of the current users is in the collection LikedBy.
var usersLiked = item.get_item('LikedBy');
likes = item.get_item('LikesCount');
if (!SP.ScriptHelpers.isNullOrUndefined(usersLiked)) {
for (var i = 0; i &amp;amp;lt; usersLiked.length; i++) {
var user = usersLiked[i];
if (user.$1E_1 === _spPageContextInfo.userId) {
didUserLiked = true;
}
}
}
var span = $('span.MyLikes[listid=' + listID + '][itemid=' + itemID +']');
span.data('userliked',didUserLiked);
if(didUserLiked)
span.next().text("Unlike");
else
span.next().text("Like");
span.text(likes);
}),
Function.createDelegate(this, function (sender, args) {
//Custom error handling if needed
console.log('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}));
}

What I’ve decided to do is to set a jQuery data attribute on the element that holds the number of likes so that I can get the value from there whenever and wherever I like, that’s done by the span.data(‘userliked’,didUserLiked); line, and then to get that value you just need to span.data(‘userliked’); and be done with it.

The other thing I think I need to explain is that I’m changing the value of the Text for the like/unlike here instead, where I first tried to do it (the Display Template) simply because it needs to be done asynchronously and as the display template goes item by item it won’t wait until you get the result it would just move on and ignore the whole thing, so in the end this function would also change that text accordingly from the success function of the async call.

Now I can show you the other two functions which could be just one, but I just felt like splitting them…

function SetLike(sender, listID, itemID){
var didUserLiked = $(sender).prev().data('userliked');
setActualLike(listID, itemID, didUserLiked);
return false;
} 

function setActualLike(listID, itemID, didUserLiked) {
var span = $('span.MyLikes[listid=' + listID + '][itemid=' + itemID +']');
var countLikes = span.text();
var aContextObject = new SP.ClientContext();
EnsureScriptFunc('reputation.js', 'Microsoft.Office.Server.ReputationModel.Reputation', function() {
Microsoft.Office.Server.ReputationModel.Reputation.setLike(aContextObject, listID.substring(1, 37), itemID, !didUserLiked);
aContextObject.executeQueryAsync(function() {
if(didUserLiked) {
countLikes--;
span.next().text("Like");
} else {
countLikes++;
span.next().text("Unlike");
}
span.text(countLikes);
span.data('userliked',!didUserLiked);
}, function(sender, args) {
// Custom error handling if needed
});
});
}

That concludes the JavaScript part. So…

Let’s go back to the Display Template

Now we need to do make this whole thing work… So we need to call the functions when needed and pass them the values of the ListID and ListItemID managed properties. So let’s start with the JavaScript part of the display template:

var listID = $getItemValue(ctx, "ListID").value;
var itemID = $getItemValue(ctx, "ListItemID").value;
if(listID != null && itemID != null)
getUserLikedPage(listID, itemID);

This will get you the ListID and ListItemID properties on two handy javascript variables and if they are not null they will be sent to the getUserLikedPage from the separate JS file. Then we need to change the HTML part so that you can display the things that you want displayed, here’s that code:

<div id="_#= $htmlEncode(itemId) =#_" name="Item" data-displaytemplate="My_DisplayItem" class="ms-srch-item" onmouseover="_#= ctx.currentItem_ShowHoverPanelCallback =#_" onmouseout="_#= ctx.currentItem_HideHoverPanelCallback =#_">
_#=ctx.RenderBody(ctx)=#_
<div>Likes: <span class="MyLikes" ListID="_#= listID =#_" ItemID="_#= itemID =#_"></span><a onclick="SetLike('_#= listID =#_', '_#= itemID =#_');"></a></div>;
<div id="_#= $htmlEncode(hoverId) =#_" class="ms-srch-hover-outerContainer"></div>
</div>

As you can see I’ve also added the ListID and ListItemID properties to the span as attributes to be able to find that easily with my jQuery.

With this code you should be getting your likes on the search results and being able to Like or Unlike from those same results (if you have set the Display Template correctly and activated the Rating features of the list).

If you have any questions feel free to ask and I’ll try to answer them below.

This is a repost from my WordPress blog: http://sanmaziri.wordpress.com/2014/10/10/fully-functional-likes-in-search-results-sharepoint-2013/

About the author 

Santiago Mazziotti Irigoyen