This post is just another example about JSLink you can find on web. This post is about show follow/Unfollow Document link in List-view. The solution is simple. Add a text column on the List (Say FollowLink) and hide this column in forms. Include the column in Listview. Link the following JSLink code in Listview webpart.
var SPOFieldCustomizations = window.SPOFieldCustomizations || {}; SPOFieldCustomizations.CustomizeFollowLinkFieldRendering = function () { var fieldJsLinkOverride = {}; fieldJsLinkOverride.Templates = {}; fieldJsLinkOverride.OnPostRender = postRenderHandler; fieldJsLinkOverride.Templates.Fields = { // Make sure the Priority field view gets hooked up to the GetPriorityFieldIcon method defined below // we have to update the column name here 'FollowLink': { 'View': SPOFieldCustomizations.GetFollowLinkFieldMarkup } }; // Register the rendering template SPClientTemplates.TemplateManager.RegisterTemplateOverrides(fieldJsLinkOverride); }; SPOFieldCustomizations.GetFollowLinkFieldMarkup = function (ctx) { var followLinkMarkup = ""; if (ctx.CurrentItem.FSObjType === "0") { followLinkMarkup = '<a class="ms-profile-followLink ms-heroCommandLink" href="javascript:;">' + '<span class="ms-profile-followHeroImageParent">' + '<img data-toggle="tooltip" data-placement="right" title="" id="Img' + ctx.CurrentItem.ID + '" src="/_layouts/15/images/gears_anv4.gif?rev=35" class="ms-profile-followHeroImage" ></img>' + '</span>' + '</a>'; SPOFieldCustomizations.isFollowed('/' + ctx.CurrentItem.FileRef, 'Img' + ctx.CurrentItem.ID); } return followLinkMarkup; }; SPOFieldCustomizations.isFollowed = function (documentUrl, imgid) { window.Utilities.Social.REST.LoadIsFollowed(documentUrl, _spPageContextInfo.webAbsoluteUrl, 1, function (responseData) { jsonObject = JSON.parse(responseData.body); if (jsonObject.d.IsFollowed === true) { $('#' + imgid).attr("title", "Click to Unfollow").attr('data-followed', '1') .attr('src', '/_layouts/15/images/socialcommon.png?rev=33') .addClass("unFollow") } else { $('#' + imgid).attr("title", "Click to Follow").attr('data-followed', '0') .attr('src', '/_layouts/15/images/socialcommon.png?rev=33') .removeClass("unFollow"); } $('#' + imgid).click(function () { var FollowStatus = $(this).attr('data-followed'); var url = ''; if (FollowStatus === '1') url = _spPageContextInfo.webAbsoluteUrl + '/_api/social.following/stopfollowing'; else if (FollowStatus === '0') url = _spPageContextInfo.webAbsoluteUrl + '/_api/social.following/follow'; if (url !== '') { SPOFieldCustomizations.toggleFollow(url, documentUrl, imgid, FollowStatus); } }); }, function (s, a, errMsg) { $('#' + imgid).text(errMsg); }); }; SPOFieldCustomizations.toggleFollow = function (url, documentUrl, imgid, FollowStatus) { window.Utilities.Social.REST.ToggleFollow(url, documentUrl, _spPageContextInfo.webAbsoluteUrl, 1, function (responseData) { var jsonObject = JSON.parse(responseData.body); var isfollowed = jsonObject.d.Follow; var stoppedFollowing = jsonObject.d.StopFollowing; if (isfollowed !== undefined) { $('#' + imgid).attr('title', 'Click to Unfollow').attr('data-followed', '1') .addClass("unFollow"); } else { $('#' + imgid).attr('title', 'Click to Follow').attr('data-followed', '0') .removeClass("unFollow"); } }, function (s, a, errMsg) { $('#' + imgid).text(errMsg); }); } function postRenderHandler(ctx) { // code to execute after view render } // Call the function. SPOFieldCustomizations.CustomizeFollowLinkFieldRendering();
There are few utility function calls inside this JSLink code to follow/unfollow documents. The code looks like
function LoadAndExecuteSodFunction(scriptKey, fn) { if (!ExecuteOrDelayUntilScriptLoaded(fn, scriptKey)) { LoadSodByKey(NormalizeSodKey(scriptKey)); } } RegisterSod('/_layouts/15/sp.requestexecutor.js'); window.Utilities = window.Utilities || {}; window.Utilities.Social = window.Utilities.Social || {}; window.Utilities.Social.REST = window.Utilities.Social.REST || function () { var LoadIsFollowed = function (documentOrSiteUrl, siteurl, actortype, successcallback, failcallback) { var requestinfo = { url: siteurl + '/_api/social.following/isfollowed', method: "POST", body: JSON.stringify({ "actor": { "__metadata": { "type": "SP.Social.SocialActorInfo" }, "ActorType": actortype, "ContentUri": documentOrSiteUrl, "Id": null } }), headers: { "accept": "application/json;odata=verbose", "content-type": "application/json;odata=verbose" }, success: function (responseData) { successcallback(responseData); }, error: function (s, a, errMsg) { failcallback(s, a, errMsg); } }; LoadAndExecuteSodFunction('sp.requestexecutor.js', function () { var executor = new SP.RequestExecutor(siteurl); executor.executeAsync(requestinfo); }); }; var ToggleFollow = function (url, documentOrSiteUrl, siteurl, actortype, successcallback, failcallback) { var requestinfo = { url: url, method: "POST", body: JSON.stringify({ "actor": { "__metadata": { "type": "SP.Social.SocialActorInfo" }, "ActorType": actortype, "ContentUri": documentOrSiteUrl, "Id": null } }), headers: { "accept": "application/json;odata=verbose", "content-type": "application/json;odata=verbose" }, success: function (responseData) { successcallback(responseData); }, error: function (s, a, errMsg) { failcallback(s, a, errMsg); } }; LoadAndExecuteSodFunction('sp.requestexecutor.js', function () { var executor = new SP.RequestExecutor(siteurl); executor.executeAsync(requestinfo); }); }; return { LoadIsFollowed: LoadIsFollowed, ToggleFollow: ToggleFollow}; }();
Good morning, I am trying to add the follow/unfollow functionality to my list. I have just used the exact code you show here and I am only seeing the gears_anv4.gif. it looks like the code is not going past the GetFollowLinkFieldMarkup function, am I missing something?
LikeLiked by 1 person
Were you able to figure it out? I’m thinking you might have given the column name incorrect, in my case it is “FollowLink” (look at your column internal name). add that column to your list, and add the Script as JSLink. Did you see any JS errors console?
LikeLike
Does this script only work for the online version, or will it work for on-premise as well.
LikeLike
It works in online and on-premises as well.
LikeLike
Hi, This is exactly what I’ve been looking to do, but I’ve tried this but I am getting the same problem as Randy – I am only seeing the gears_anv4.gif spinning.
The code at line 30 never fires for some reason.
Where should the code in your second block go? At the moment I have added it to the same javascript file that contains the first code block. Is there anything else that could be missing? I have used the exact same column name: “FollowLink”.
LikeLike
You can put the second block JS in the same file. Did you get any console error? if not, can you tell me what is the response of the api call in network tab? Also put a break point at 70th line in second block to make sure you are loading sp.requestexecutor.js. There is also some css written for the UI I shown in screenshot which is not included here.
LikeLike
Thanks for getting back to me – there is no console error and no sign of the api call in the network tab.
sp.requestexecutor.js does seem to be loading OK I think.
When debugging it goes into LoadIsFollowed at the following line:
window.Utilities.Social.REST.LoadIsFollowed(documentUrl, _spPageContextInfo.webAbsoluteUrl, 1, function (responseData) {
but when it returns responseData is null or undefined, therefore the next line of code never runs:
jsonObject = JSON.parse(responseData.body);
I’m guessing that the api call is not being called for some reason?
LikeLike