Customizing ProfileInfo webpart in SharePoint 2013 MySite


This blog explains a quick and dirty way to customize AboutMe webpart in MySite.

Method 1:

mysite

I had a requirement to hide “SHOW MORE/SHOW LESS” buttons in the “ProfileInfo” Webpart pages for all users. This OOB webpart doesnt have any provisions to disable this. Since these pages are loaded from person.aspx of my site root site collection, we can disable these buttons by adding script editor webpart. The steps are 1) Open Person.aspx using SPD 2013 in advanced mode 2)Find the ID of “ProfileInfowebart” in my case its “g_33faa336_e58c_4bbc_a81a_1704ccaff199” 3) Add a script link webpart with the following code (Replace the webpart ID with your’s)

_spBodyOnLoadFunctionNames.push("removeShowless");
function removeShowless()
{SP.SOD.executeFunc('portal.js',ShowHideProfileInfoDetails,
function() {
ShowHideProfileInfoDetails('ctl00_ctl41_g_33faa336_e58c_4bbc_a81a_1704ccaff199_ProfileViewer', 'ctl00_ctl41_g_33faa336_e58c_4bbc_a81a_1704ccaff199_ProfileViewer_showHideLink&', '','', ctl00_ctl41_g_33faa336_e58c_4bbc_a81a_1704ccaff199_ProfileViewer_hidden');});
}

4) Save and publish the page.

How this works? 

SP.SOD.executeFunc()

Microsoft uses SP.SOD.executeFunc(key, functionName, fn) (Script On Demand) extensively to load on demand scripts. Refer this fanstastic blog post by Christain Glessner for more details.

key” parameter must match to the ScriptLink’s Name property (Use small letters for key, because an issue with string normalizing in RegisterSodDep).

functionName” awaits a type name of an ASP.NET AJAX JavaScript class. ExecuteFunc first checks if the AJAX class has already been registered, when not it checks additionally if a SOD with this key has already been loaded and finally it will load the SOD. Load means adding dynamically the corresponding script tag to the HTML head. The check for the type helps to ensure that the script has not been already loaded via an usual script tag before. When you don’t want to work with AJAX JavaScript classes you can use “null” value for the functionName.

fn defines a callback that will be executed when the SOD has signaled finished loading.

In the above code, the function ShowHideProfileInfoDetails() is modified to hide the buttons. (Use the   IE developer tools to understand the original implementation in the page and just reverse it)

Method 2:

Then of course there is always CSS.
You could do this:

/*you will have to locate your ID number and replace in the line below*/
#ctl00_ctl32_g_dc992ff0_0776_4fd4_ad6f_cda68ca93c89_ProfileViewer_showHideLink
{
display:none;
}
.ms-profile-hiddenDetails
{
display:block !important;
overflow:visible !important;
}

Thanks Stone for suggesting this.

Advertisements

Contact Search using SPServices


Recently I have been working with a client to develop a webpart to search all the contacts list in a site. Here are the limitations with this requirement

  • This should be implemented in #Office365 environment and also compatible with any SharePoint 2010.
  • Client may have many contact lists but all inheriting from contact list template

Since the webpart is implemented on Office365, Sandboxed webparts or Content Editor Webpart is the only option. I am not a big fan of Sandboxed webparts. This blog explains to how implement this using CEWP and #SPServices.

Why #SPServices: SPServices is a SOAP based open source Jquery library from Marc Anderson  which abstracts SharePoint web services and makes the life easy for the developers.

This is how the webpart is going to look finally.

Capture

Here is the code:

HTML for Search Box:

<table><tbody><tr><td align="right">First Name:</td>
<td align="left"><input id="firstname" type="text"/></td></tr>
<tr><td align="right">Mobile:</td>
<td align="left"><input id="mobile" type="text"/></td></tr>
<tr><td align="right">Address:</td>
<td align="left"><input id="address" type="text"/></td></tr></tbody></table>
<p><input id="sb" type="button" value="Search"/> </p>
<ul id="searchResults"></ul>

Generate SPQuery and pass to the function: 

Before executing this make sure references are added to Jquery and SPServices

$(document).ready(function () {
$("#sb").click(function(){
$("#searchResults").empty();
var query = "";
var key = "";

//Build Query from input
if($("#firstname").val()){
key = $("#firstname").val();
query = "<Query><Where><Or><Contains><FieldRef Name='FirstName'/><Value Type='Text'>"+ key +"</Value></Contains><Contains><FieldRef Name='Title'/><Value Type='Text'>"+ key +"</Value></Contains></Or></Where></Query>";
}
else if ($("#mobile").val()){
key = $("#mobile").val();
query = "<Query><Where><Contains><FieldRef Name='WorkPhone' /><Value Type='Text'>"+ key +"</Value></Contains></Where></Query>";
}
else if ($("#address").val()){
key = $("#address").val();
query = "<Query><Where><Contains><FieldRef Name='WorkAddress' /><Value Type='Text'>"+ key +"</Value></Contains></Where></Query>";
}

// Pass query to Function
if(query)
sendQuery(query);
else
$("#searchResults").append("Please enter atleast one value");

//If no results found
if (!$("#searchResults").html())
{
$("#searchResults").append("No Results Found");
}

});
});

Search results using SPServices:

function sendQuery(spQuery)
{
var thisSite = $().SPServices.SPGetCurrentSite();
//function to get all the lists
$().SPServices({
operation: "GetListCollection",
webURL: $(this).attr("WebFullUrl"),
async:false,
ompletefunc: function(xData, Status) {
$(xData.responseXML).find("List").each(function(){
var listTitle = $(this).attr("Title");
$().SPServices({
operation: "GetListContentTypes",
async: false,
listName: $(this).attr("Title"),
completefunc: function (xData, Status) {
//alert(xData.responseXML.xml);
$(xData.responseXML).find("ContentType").each(function() {

//Find all the lists with "Contact" type content

if($(this).attr("Name") == "Contact"){

$().SPServices({
operation: "GetListItems",
async: false,
listName: listTitle,
CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='FirstName' /><FieldRef Name='LastName' /><FieldRef Name='WorkPhone' /><FieldRef Name='WorkAddress' /><FieldRef Name='EncodedAbsUrl' /></ViewFields>",
CAMLRowLimit: 5,
CAMLQuery: spQuery,
completefunc: function (xData, Status){
if(!xData.responseXML)
$("#searchResults").append("No Results found");
$(xData.responseXML).find("z\\:row").each(function(){
var resultURL = "";

//URL of the contact list item display form

resultURL = scope + "/DispForm.aspx?ID=" + $(this).attr("ows_ID");
var url = $(this).attr("ows_EncodedAbsUrl") + "";
var liHtml = "<li><a href='" + resultURL + "'>" + $(this).attr("ows_FirstName")+" " + $(this).attr("ows_Title") + "</a></li>";
$("#searchResults").append(liHtml);

});

}

});

}

});
}
});
})
}
});
}

Same piece of code block can be used in #Office365 or #SP2010 sites