Reassign a workflow task – Task update was not accepted. To edit a task associated with a workflow task process, you must be the person to whom the task is currently assigned.


Hi guys,

Recently one of my client has faced this issue while reassigning a task of default Approval workflow. Here is the screen shot:

      

SharePoint by default only allows the assignee to re-assign the task. If you try to re-assign a task that is not assigned to you, you get the following message:

Task update was not accepted. To edit a task associated with a workflow task process, you must be the person to whom the task is currently assigned.

Solution

To overwrite this behaviour:

  1. Open SharePoint Designer
  2. Open the Workflow you wish to modify.
  3. On the step where you start the workflow task ‘Start <workflow task name> process on Current Item with…’, right click on the task name.
  4. Select Properties and look for the attribute TaskProcessOwner.
  5. Click on the ‘‘ button to select a group or specific user.
  6. You may wish to create a SharePoint group specifically for this purpose. All members of this group will have permissions to re-assign tasks that are assigned to other people.

Hope this post help you to fix this error.

Happy SharePointing.

Advertisements

SharePoint Online/2013 Replace no results default text ‘Nothing here matches your search’ from search results web part


 

As we all aware, SharePoint search have great potential to provide very powerful search solution. Couple of new webparts are added in SharePoint 2013, like Content Search web part for which I should use rather a word “Smart” search web part. With a new rendering mechanism, content search webpart becomes more and more simple to edit and customize. That mechanism is called “Display Templates” and these are based upon simple Json to HTML templates.

I recently has faced a project scenario, where I was asked to replace the part of search result web part and I provided a solution by updating search display template.

Requirement:  When we add a search result web part on any result page along with a search text box web part to enter search keywords. Search results will be displayed in web part if keyword matches any text. When we add both these web parts on page and before entering the search term also the results web part show  “Nothing here matches your search” (as shown in below image), which my users want to modify based on their content and want to add some useful links into it.

Blog1

 

Solution:

Initially, I thought that this may be easily updated using some web part property, but after researching about it, I found that there are html/json files called, display templates, which are responsible for rendering this text. Let me explain how to find them and which Display Template we need to customize in order to achieve our target.

All kind of Display Templates are stored at the one location under master page gallery. Here are the steps to reach out to the html file.

  1. Open the site collection.
  2. Navigate to Site Settings.
  3. Under Web Designer Galleries click on Master pages and page layoutsBlog2
  4. Now click on the folder Display Templates and then Search.     Blog3
  5. Under the search folder you will find html and .Js files present.
  6. We are more intereste d in ‘Control_SearchResults.html’. Make sure you click in html file not JS file with same name.

If you are not familiar with this structure then you must be thinking that “Why JS and HTML files with two names?”

In brief, actually display templates are JS files only but just to the sake of simplicity MS has provided HTML so that it is easier to modify/edit display templates. There is out of box event receiver attached to this list when there is any modification detected in HTML file, a new version of JS will be generated by the event receiver. Display Templates are actually split into two different files, the Control and the Item.

Control Display Template

This is the part of your design that does not get repeated as each items gets loaded in the Search Results. It’s the container around and where you refer to any custom CSS or JS files you may want to use.

Put simply, it’s the box where search results will be loaded.

Item Display Template

This is where you design how each item will look like and which managed properties from the result item will be used and where on the design. If I take my example above, that’s all in the Item Display Template. The size of the rectangle, where the Title goes and where the Description goes as well as the animation itself.

Search Results web part of SharePoint uses ‘Control_SearchResults.html’ display template which is available under Master Page Library –> Display Templates –> Search.

Now lets start actual modification of the template:

  1. Download a copy of ‘Control_SearchResults.html’. Click Control_SearchResults.html template file and Download a Copyblog5
  2. Rename the downloaded file as Control_SearchResults_Custom.html. Open the control template file in any of your preferred editors such as SharePoint Designer and customize the file, as per our need.blog6
  3. Change the Title in this HTML file, this title will be available for selection in web part properties.
  4. Now we want to get the search text entered in to search box web part, for that we will use ctx object as following ctx.DataProvider.get_currentQueryState().k
  5. Search if(ctx.ClientControl.get_shouldShowNoResultMessage()){    line in HTML file (as shown in below image).
    Search_Result_SP_2013_Display_Template_1
  6. Find the unordered list just below that code and modify it according to your need.
  7. For example if you don’t want to show any message until user enters some keyword, replace if statement line with
    var currentQueryTerm = ctx.DataProvider.get_currentQueryState().k; if(ctx.ClientControl.get_shouldShowNoResultMessage() && currentQueryTerm!=””){
    (As shown in below image)
    Search_Result_SP_2013_Display_Template_2
  8. Save the modified HTML file.
  9. Go to Master Page Library –> Display Templates –> Search and upload new control template.
  10. You will see that respective ‘Control_SearchResults_custom.js’ will be created by SharePoint.
  11. Now go to your page where Search Result web part is added, edit Search results web part. Under Display Templates section select newly uploaded display template.( as shown in below image).Select our custom control display template.

  12. Save the changes and that’s it, you will see the  expected result.

Hope this information is helpful for you to modify display templates.

Happy SharePointing 🙂

 

SharePoint CSOM for beginners: Get Current User details


Hi Guys,

This blog is targeted to developers who are novice to the client side object model in SharePoint. SharePoint apps by default provides a basic stub for getting user details inside app. But sometimes it is required to add client side code in simple script file to get user information. I hope this information will also be helpful starters of client side object model.

Pre-requisites:

1) Any version of SharePoint installed: SP 2013, SP 2010 or SP Online

2) A web application and a root site collection inside it. It does not matter whether site is team site or any other type of site.(Note: In case of publishing site you need to enable sp.js file loading).

3) SharePoint Designer installed.

Step I: Create a custom script file

A script file is required in order to place CSOM code to be executed. Well, here depending upon usability user can chooses any one of these two locations to create this file:

List or Style library: It will be hard to update script file if it is placed under style library. Every time one have to update the file in SP Designer in order to make any changes or one have to upload the latest file each time in case of any update.

15 hive folder: This is my favorite place in order to do such kind of research. Create a dummy folder under “15/Template/layouts/dummy”.

I am referring second approach as it is very comfortable to update the files in 15 hive. Now open the dummy folder and create a JS file there with any name say, CSOMDemo.js. Let this file blank as of now.

Step II: Refer a custom script file

Once custom JS file is created, now next is to refer this file to master page so that it will be utilized by SharePoint. There are also many option to refer the file: Master page, Page layout(in case of publishing site), using content editor web part etc.

For this blog I am referring the script file to master page. In order to do same, Open the site using SP Designer and click on All Files > _catalogs >  masterpage > seattle.master(for team site). Then right click on the file and select the option “Edit File in Advanced Mode”.

Capture1                        Capture2

Now find out the head section add following lines:

<script type=”text/javascript” src=”https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js “></script>
<script type=”text/javascript” src=”/_layouts/15/dummy/Script/CSOMDemo.js”></script>

 

Names can vary according to your naming conventions. But one these lines are placed in master page, all site pages will be registered and enabled with jQuery and custom scripts.

Step III: Write CSOM Code

Open the custom script file and paste the following code in side it.

var currentUser;
$( document ).ready(function() {
console.log(‘ready’);
url = window.document.location.href;

// In case of Publishing site please use following code line

// SP.SOD.executeFunc(‘sp.js’, ‘SP.ClientContext’, init);

ExecuteOrDelayUntilScriptLoaded(init,’sp.js’);

function init(){
var context = new SP.ClientContext.get_current();
var web = context.get_web();
currentUser = web.get_currentUser();
currentUser.retrieve();
context.load(web);
context.executeQueryAsync(
function(){
//On success function
console.log(‘init succeeded..’);
console.log(currentUser.get_loginName());
console.log(currentUser.get_id());
console.log( currentUser.get_title());
console.log(currentUser.get_email());
},
function(){ //On fail function
alert(‘Error: ‘ + args.get_message() + ‘\n’ + args.get_stackTrace());
}
);
}
});

That all. Here is the result:

Capture3

 

Hope that code will be helpful for you.

Happy SharePointing 🙂

SharePoint get followed sites using REST Api


Recently I was tasked with a project requirement that the user should be able to see list of content he/she followed. To me this sounds much like using the following feature of SharePoint 2013 which allows you to follow documents, sites, people and tags. Also, we don’t want the user to navigate to his/her mySite and have a look on to the content followed.

We can use the SharePoint 2013 Representational State Transfer (REST) service to do the same tasks you can do when you use the .NetCSOM, JSOM.

Here I explain how to retrieve the site name and URL followed by the current user in SharePoint 2013 using a client object model (REST API and JavaScript) and displaying it in the SharePoint page.

1. Create a new page and a Content Editor Webpart (CEWP).

Create a New page

2. Edit the web part that was added to the page.

Edit the web part

3. Upload your text file script into the site assests and copy the path of the text file and paste it into the Content link in CEWP.

4. Output

Output

Code

The following example shows how to retrieve all of the following sites:

<html>
<head>
<script type=”text/javascript” src=”//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js”></script>

<script type=”text/javascript”>
var followingManagerEndpoint;
var followedCount;

var followingEndpoint;
var URL;
var website;
var clientContext;

SP.SOD.executeFunc(‘sp.js’, ‘SP.ClientContext’, loadWebsite);
function loadWebsite() {
clientContext = SP.ClientContext.get_current();
website = clientContext.get_web();
clientContext.load(website);
clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);
}

function onRequestSucceeded() {

URL = website.get_url();
followingManagerEndpoint = decodeURIComponent(URL) + “/_api/social.following”;

getMyFollowedContent();
}

function onRequestFailed(sender, args) {
alert(‘Error: ‘ + args.get_message());
}

// Get the content that the current user is following.
// The “types=14” parameter specifies all content types
// (documents = 2 + sites = 4 + tags = 8).
function getMyFollowedContent() {

$.ajax( {
url: followingManagerEndpoint + “/my/followed(types=14)”,
headers: {
“accept”: “application/json;odata=verbose”
},
success: followedContentRetrieved,
error: requestFailed
});
}

// Parse the JSON data and iterate through the collection.

function followedContentRetrieved(data) {
var stringData = JSON.stringify(data);
var jsonObject = JSON.parse(stringData);
var types = {
1: “document”,
2: “site”,
3: “tag”
};

var followedActors = jsonObject.d.Followed.results;
var followedList = “You’re following items:”;

for (var i = 0; i < followedActors.length; i++) {
var actor = followedActors[i];
followedList += “<p>The ” + types[actor.ActorType] + “: \”” +actor.Name + “\”</p>”+”<p>Site URL ” + “: \”” +
actor.Uri+ “\”</p>”;;
}
$(“#Follow”).html(followedList);
}

function requestFailed(xhr, ajaxOptions, thrownError) {
alert(‘Error:\n’ + xhr.status + ‘\n’ + thrownError + ‘\n’ + xhr.responseText);
}

</script>
</head>
<body>
<div id=”Follow”></div>
</body>
</html>

Happy SharePointing 🙂

Send message to client app part using a “PostMessage Shim”


In this post, I’ll walk through how to use the postMessage api to enable cross-frame communication between your Client App Parts and the hosting SharePoint page, to make your SharePoint App Parts more dynamic and responsive to changes in the parent page.

Overview

In the SharePoint 2013 App Model, Client App Parts are implemented as iframes into pages hosted in App Webs or Provider Hosted web applications. Because SharePoint apps are hosted on different domains, the iframes can’t use javascript to access the parent window and get information from the hosting page. This is a good thing. You wouldn’t want a Client App Part that you installed from the marketplace to be able to see the list of customers on that List View web part that sits right next to it on the page. But it does make it very hard as a developer to give Client App Parts more dynamic page information to work with. The only contextual info a Client App Part can get is through Client App Part properties.

Normal SharePoint Web Parts have a number of ways of getting initialization data from the hosting page when they first load up:

  1. Web Part Properties (Tool Pane)
  2. Web Part Connections (Passing info from Web Part to Web Part)
  3. Host Page QueryString
  4. Reading Hidden Fields or other form elements on the page
  5. Built-in SharePoint objects like _spPageContextInfo
  6. Reading the metadata of the host page

Unfortunately, SharePoint Client App Parts can only get information from the first option, through Client App Part Properties. When you build your Client App Part with custom properties, they appear in the App Part’s tool pane when you edit the App Part, similar to normal Web Part toolpane properties. Client App Part properties are a little different though – setting these actually appends a querystring parameter to the App Part’s iframe src attribute, which your App Part page can then read when it starts up. That’s good for setting a one-time configuration of your App Part, but you can’t change any of those properties dynamically in response to changes in the host page.

In this post, I’ll show you how to pass additional data from the host page to your Client App Parts via the postMessage api, effectively opening the door to leveraging 2-6 above. The example I’ll show will be an App Part placed on the MySite Host’s About Me page. The App Part will read the host page’s accountname querystring parameter to determine which user profile is being viewed, and will display some basic profile information about that user.

The postMessage API

The postMessage API was designed to enable safe, cross-domain communication between windows or iframes. Essentially each window needs to opt-in to accepting communications from other cross-origin/cross-domain windows. Any window or iframe can send messages to another window or iframe just by calling the postMessage method. If the target window hasn’t opted-in to listen for these messages, the messages are just silently ignored.

Requesting Information from the Host Page

The first step in getting this to work is to configure your Client App Part page to send a request to the host page, and to configure a listener for the host page’s response.

To start this out, using Visual Studio 2013, I created a new SharePoint App project called PostMessageApp, added a Client Web Part (Host Web) called PostMessageAppPart, and created a new page for the App Part called PostMessageAppPartPage.aspx. I gave the App Part the Read permissions to the User Profile (Social) permission set.

The basic solution structure.

In the App Part page, I added some basic HTML markup:

1
2
3
4
5
6
7
8
9
<body>
    <div>
        Host page's full url:<br />
        <textarea id="hostpageurl" readonly="readonly" style="width:100%;height:75px;overflow:scroll;" ></textarea><br /><br />
        First name: <span id="firstname"></span><br />
        Last name: <span id="lastname"></span><br />
        Department: <span id="department"></span><br />
    </div>
</body>

Here is what the app part looks like empty:

Empty App Part

In the newly created App Part page, I added a javascript function to the page head called getQueryStringParameter which is needed to extract querystring information. You’ve probably seen a similar function in many of the SharePoint Hosted App code samples on the internet. This version below includes an overload to get a querystring value from a passed-in url (rather than the current document’s url), which will be used later:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function getQueryStringParameter(key, urlToParse) {
    /// <signature>
    /// <summary>Gets a querystring parameter, case sensitive.</summary>
    /// <param name="key" type="String">The querystring key (case sensitive).</param>
    /// <param name="urlToParse" type="String">A url to parse.</param>
    /// </signature>
    /// <signature>
    /// <summary>Gets a querystring parameter from the document's URL, case sensitive.</summary>
    /// <param name="key" type="String">The querystring key (case sensitive).</param>
    /// </signature>
    if (!urlToParse || urlToParse.length === 0) {
        urlToParse = document.URL;
    }
    if (urlToParse.indexOf("?") === -1) {
        return "";
    }
    var params = urlToParse.split('?')[1].split('&');
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split('=');
        if (singleParam[0] === key) {
            return decodeURIComponent(singleParam[1]);
        }
    }
    return "";
}

After including the querystring function, I added the following script underneath it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function () {
    var getHostPageInfoListener = function (e) {
        /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
        console.log("postMessage response received: " + e.data);
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error) {
            console.log("Unable to parse the response from the host page.");
            return;
        }
    }
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', getHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', getHostPageInfoListener);
    }
    // Send the host page a message
    var hostPageMessage = {};
    hostPageMessage.message = "getHostPageInfo";
    var hostPageMessageString = JSON.stringify(hostPageMessage);
    window.parent.postMessage(hostPageMessageString, document.referrer);
    console.log("Sent host page a message: " + hostPageMessageString);
})();

This script accomplishes two things: 1) it sends a message to the host page requesting information, and 2) it registers a listener (callback) for the response from the host page. Notice that I’m sending a stringified JSON object to the host page, which I will reconstitute later. When you send messages between windows, you are just sending one string of data. You can choose to send XML, plain text, or even stringified JSON.

At this point I can send a message to the host page, but since the host page isn’t listening for it yet, the message will just silently get ignored.

Sending Information Back to the Client App Part Page

The next step in getting this to work is to configure the host page to listen and respond to the request for more information. For this, some javascript must be placed on the host page to opt-in to receiving messages from other windows. You can add javascript to a SharePoint page in a variety of ways, through a Content Editor or Script Editor web part, by editing the page or page layout in SharePoint Designer, or by adding the script directly to a masterpage.

For this example, I am going to edit the About Me page in a MySite Host site collection (“Person.aspx”) with SharePoint Designer to add the following script. I am going to add the script to the PlaceHolderAdditionalPageHead area:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<asp:Content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
<SPSWC:ActivityFeedLink Consolidated="false" runat="server"/> 
<SPSWC:MySiteHideDiv HideRibbonRow="true" runat="server"/>
<script type="text/javascript">
(function() {
    var sendHostPageInfoListener = function (e) {
        var messageData;
        try
        {
            messageData = JSON.parse(e.data);
        }
        catch (error)
        {
            console.log("Could not parse the message response.");
            return;
        }
        // Construct the return data to send to the app part
        var returnData = {};
        returnData._spPageContextInfo = _spPageContextInfo;
        returnData.hostPageURL = document.URL;
        var returnDataString = JSON.stringify(returnData);
        e.source.postMessage(returnDataString, e.origin);
        console.log("Sent app part iframe message: " + returnDataString);
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', sendHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', sendHostPageInfoListener);
    }
})();
</script
</asp:Content>

The code above does two things: 1) Opts-in to listen for messages from other windows, and 2) Sends JSON data about the current page to the window that sent the request. I’ve chosen here to send a couple of pieces of information. First, I sent the full url of the host page, including any querystring parameters, by passing the document.URL. Second, I’ve also chosen to send the _spPageContextInfo object of the host page, which contains some rich data about the host page. This is just to demonstrate that you aren’t limited to sending plain text, you can serialize javascript objects from the host page as well.

With the App Part and the script above on the page, I can now see the communication back and forth between the windows in the console, and can view the returned data in a watch window. Notice the host page’s _spPageContextInfo is fully deserialized and expanded into a javascript object for use in the App Part.

The returned data

Securing the Requests

By putting these scripts in place, I have allowed my host page to give information to any window or iframe that sends a request message. It’s a good idea to make this more secure, and only give host page information out to windows that you trust. You can get as restrictive or permissive as you want/need with this validation.

For home-grown side-loaded SharePoint apps, this could be as simple as passing a shared key around, and checking on both sides. To demonstrate this basic validation, I’ll add a couple of lines to the code in the Client App Part page to store and send the secret key and to parse and read it from the host page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var secretKey = "mysecretkeyxyz";
(function () { 
    var getHostPageInfoListener = function (e) {
        /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
        console.log("postMessage response received: " + e.data);
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error) {
            console.log("Unable to parse the response from the host page.");
            return;
        }
        if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
            console.log("Could not validate the message.");
            return;
        }
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', getHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', getHostPageInfoListener);
    }
    // Send the host page a message
    var hostPageMessage = {};
    hostPageMessage.secretKey = secretKey;
    hostPageMessage.message = "getHostPageInfo";
    var hostPageMessageString = JSON.stringify(hostPageMessage);
    window.parent.postMessage(hostPageMessageString, document.referrer);
    console.log("Sent host page a message: " + hostPageMessageString);
})();

On the host page, I’ve also added some validation code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
(function() {
    var sendHostPageInfoListener = function (e) {
        var secretkey = "mysecretkeyxyz";  
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error)
        {
            console.log("Could not parse the message response.");
            return;
        }
        if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
            console.log("Could not validate message.");
            return;
        }
        // Validate that it contains the expected instruction
        if (messageData.message !== "getHostPageInfo") {
            return;
        }
        // Construct the return data to send to the app part
        var returnData = {};
        returnData.secretKey = secretKey;
        returnData._spPageContextInfo = _spPageContextInfo;
        returnData.hostPageUrl = document.URL;
        var returnDataString = JSON.stringify(returnData);
        e.source.postMessage(returnDataString, e.origin);
        console.log("Sent app part iframe message: " + returnDataString);
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', sendHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', sendHostPageInfoListener);
    }
})();

For the purposes of this example, this basic validation will suffice to demonstrate the point, but I would recommend beefing this up in your own implementations.

Now, on to the last part, consuming the information.

Consuming the Data

Once you’ve got these hooked up, you can work with the data. In the App Part Page, I modified the getHostPageInfoListener function with some code to get the accountname querystring parameter from the data the host page returned, and to query the User Profile REST api to get data about that user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var getHostPageInfoListener = function (e) {
    /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
    console.log("postMessage response received: " + e.data);
    var messageData;
    try {
        messageData = JSON.parse(e.data);
    }
    catch (error) {
        console.log("Unable to parse the response from the host page.");
        return;
    }
    if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
        console.log("Could not validate the message.");
        return;           
    }
    var appWebUrl = getQueryStringParameter("SPAppWebUrl");
    var requestUrl = "";
    var requestData = {};
    var accountName = getQueryStringParameter("accountname", messageData.hostPageURL);
    if (!accountName || accountName.length === 0) {
        console.log("Could not find an accountname querystring parameter, using the current user.");
        // Use the current user instead.
        requestUrl = appWebUrl + "/_api/SP.UserProfiles.PeopleManager/GetMyProperties";
    }
    else {
        requestUrl = appWebUrl + "/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=@v)";
        requestData["@v"] = "'" + accountName + "'";
    }
    jQuery("#hostpageurl").html(messageData.hostPageURL);
    jQuery.ajax({
        url: requestUrl,
        type: "GET",
        data: requestData,
        headers:{ Accept:"application/json;odata=verbose" },
        success: function (data) {
            var properties = data.d.UserProfileProperties.results;
            for (var i = 0; i < properties.length; i++) {
                if (properties[i].Key === "FirstName") {
                    jQuery("#firstname").html(properties[i].Value);
                }
                else if (properties[i].Key === "LastName") {
                    jQuery("#lastname").html(properties[i].Value);
                }
                else if (properties[i].Key === "Department") {
                    jQuery("#department").html(properties[i].Value);
                }
            }
        },
        error: function (jqxr, errorCode, errorThrown) {
            console.log(jqxr.responseText);
        }
    });
};

You can see the result below, where I am logged in as Adam Toth, but am viewing Harry Tuttle’s profile:

App Part displaying another user's profile information.

Conclusion

With a simple javascript shim in place on a host page, I’ve shown how much richer contextual data can be passed to a Client App Part. Until Microsoft implements an alternative method, the postMessage api remains a safe and viable option for tackling scenarios that sandbox or full-trust web parts have been able to do for some time.

Not able to Edit web part


Hi,

It is weird if you have full rights and still you are not able to edit the web parts. Well I should say its exacted in some sense. SharePoint is a product which gives flexibility to configure your portal as you want. So what is the trick behind this issue.

Let me clear it should not treated like an issue instead its a security setting which is restricting users having full permissions to even edit the web parts on web application. So question is where can I find this setting.

Central Admin > Application Management > Manage Web applications >  select your web application >Web Part Security.

As per this setting you can configure:

1) Web Part Connections: Allow users to create connection between webparts

2) Online Web Part Gallery: Allow user to access the online web part Gallery.

3) Scriptable Web Parts: Allow contributors to add and edit scriptable Web parts

We are more interested in the third setting which allows/restrick contributors to edit of add web parts.

There are two possible ways you can achieve editing web parts on the page:

I) Disable this setting I mention in Central Administration like this:
– Go to Central Admin > Application Management > Manage Web applications
-select your web application that you want to make this change on (yes, this can only be done at the web application level which kind of sucks)
-select ‘Web Part Security’
-scroll down to ‘Scriptable Web Parts’ and select ‘Allows contributors to add or edit scriptable Web Parts’
-click OK

Capture

II) If you do not want to disable this setting, give the Full Control user ‘Approve’, ‘Manage’ and ‘Designer’ permissions, in ADDITION to ‘Full Control’

Hope this blog will help you achieving what you want.

Happy SharePointing 🙂

Get Comment Count in SharePoint


Hi Guys,

In this blog I will explain how we can get the number of comments on any page/article. Prerequisites for this blog are: a list with rating enabled, an article/page/splistItem already have got comments from users and a tool like VS to code 😉

According to requirement it may be the case that one need to get item comment count using java script or c#. I will explain both way to get the comment count:

Using Javascript: This may be the case when one want to use the content search webpart or CQWP to display comment count. Followng code can be use to get the comment Count:

var linkURL = $getItemValue(ctx, “Link URL”);
linkURL.overrideValueRenderer($urlHtmlEncode);

// Get the Comments count
var soapEnv =
“<soap:Envelope xmlns:xsi=’http://www.w3.org/2001/XMLSchema-instance&#8217; xmlns:xsd=’http://www.w3.org/2001/XMLSchema&#8217; xmlns:soap=’http://schemas.xmlsoap.org/soap/envelope/’&gt; \
<soap:Body>    \
<CountCommentsOnUrl xmlns=’http://microsoft.com/webservices/SharePointPortalServer/SocialDataService’&gt; \
<url>” + linkURL + “</url> \
</CountCommentsOnUrl> \
</soap:Body> \
</soap:Envelope>”;

$.ajax({
pageurl: linkURL,
url: “/_vti_bin/SocialDataService.asmx?op=CountCommentsOnUrl”,
type: “POST”,
dataType: “xml”,
data: soapEnv,
contentType: “text/xml; charset=\”utf-8\””,
success: function(data, status, xhr){
if(data !== undefined) {
var commentCount = $(‘CountCommentsOnUrlResponse’, data).find(‘CountCommentsOnUrlResult’).text();
if(commentCount>0){
$(‘#’+ commentId +  ‘ .comments’).html(commentCount);
$(‘#’+ commentId).show();
}
else{
$(‘#’+ commentId).hide();
}
}
}
});

Using server code: You must have to know the full path of the page. That is again a challenge. In most of the cases you must be having SPListItem object. Following code can be used to get the path:

var pageUrl = item[“EncodedAbsUrl”] + item[“FileRef”].ToString().Substring(item[“FileRef”].ToString().IndexOf(“#”) + 1);

var context =SPServiceContext.Current;
var scManager =newSocialCommentManager(context);
var pageUri =newUri(pageUrl);
int count = scManager.GetCount(pageUri).ToString(CultureInfo.InvariantCulture);

Hope above code helped you. Kindly comment and share your views.

Happy SharePointing 🙂