Wednesday, April 29, 2015



In the journey of Yammer Integration with SharePoint we have seen so many aspects of Yammer and its options. We have seen to fetch the feeds from yammer, user information, conversations etc. We have touched all options to try those operations in various articles. In my last article related to Yammer I described how to choose a best option while finalizing the Yammer design.

In this article we will see how to display or get Yammer Search results in SharePoint. Earlier Yammer web part was the option to get search results in SharePoint but recently Microsoft has announced the end of support of Yammer web part. So now the available  option is Yammer REST API and we will see it in this article in details.

Following is the REST API to get the search results from the Yammer:


Parameters for this REST are:

Search: search keyword/text

Page: Integer value. Number of page. By default the value is 1. It is helpful when you implement pagination.

Num_per_page: Integer value. This helps to configure number of results per page. 20 maximum.

If everything goes correctly then you will get result in sets: messages, users, topics and groups. You get all related information about conversation like who posted it, at what time, in which group, content, etc.

Following is the sample code to get the search results. In the picture below you can see how the results look like.

Sample code:

yam.platform.request(
   {
   url: "search.json"
   , method: "GET"
   , data: { 'search': self.SearchText() }
   , success: function (msg) {     
$.each(msg.messages.messages, function () {
var summary = this.body.rich;
var path = this.web_url;
alert(summary + "  " + path);
});
});

Result image (json result):




Here a year back I have depicted how one can deeply integrate Yammer search with SharePoint search: SharePoint 2013: Deep integration of Yammer Search with SharePoint search.

Now we will move one step ahead and see how to show SharePoint results and Yammer results together. Yes, this is possible you can implement a custom component which can read data from both SharePoint and Yammer using their respective REST URLs. To learn more about the SharePoint Search REST API click here and here. As shown in below picture this component takes the search keyword/text from the user and sends it to both Yammer REST API and SharePoint REST API, Once it get response from both it shows results combined and ordered on screen/page. Following picture can help to understand the idea.



Let’s take look at each box of this component.

1.   Yammer Search REST API handler :
This handler takes the search text or key word from the JS framework and gives it to the Yammer Search REST service. This service then fetches data from the Yammer network and returns backs to the handler. The search results  are dependent on the current logged in users  access or permission. This REST service returns information of messages, users, topics and groups which is found for that particular keyword or search text. Then the handler creates an array of results and orders it by creation/publishing date and returns it to the Search Results Merger for further processing.
2   
      SharePoint Search REST API handler :
The job of this handler is same as Yammer REST handler, the only difference is it sends the search key/text to the SharePoint Search REST API. The SharePoint Search REST talks with the SharePoint Search service and returns the matched records to the handler. Handler returns the array to the Search Results Merger.
3.   
      Search Result Merger :
The task of merger is two way task. It gets the search key/text from the UI and sends it to the handlers. It also waits for the results from handlers and merge them into one result set and sorts the result by publishing date and binds the result to the UI component. I have used Knock out JS Framework here to do this task as it makes life simpler. You can prefer other frameworks.
4.       
      UI/Screen : This component interacts with the users. It takes the search key/text from the user and shows the search results on the screen.


This way you can integrate Yammer search with SharePoint search. If you want to make the component RWD compliant then it’s cherry on the cake. I will be working to transform this to SharePoint App/ web part, stay tuned!

Happy Yamming!

Saturday, April 25, 2015


Metadata is data about data; additional information about data. In SharePoint we can manage them centrally which is nothing but Managed Metadata service or Term Store service. In SharePoint you can organize the metadata in a way which suits your business.

Let’s have quick overview on some key terminology:

Group:
In SharePoint groups in context of Managed Metadata is nothing but set of Term Sets which share common security requirements. Only users who have contributor permission on Group can manage Term Sets belongs to that group.

Term Set:
Term Set is nothing but group of related Terms. Term Sets have different scope based on location of their creation: local or global.

Terms:
A term is specific word or phrase which you can associate with list item or documents. It is single item in term set. A term has a unique ID and it can have many text labels (synonyms). If you work on a multilingual site, the term can have labels in different languages.

Enough theory. Now let’s see how to work with them in SharePoint App using JSOM or ECMA scripting.

So to start with implementation, in App you first need to get host and app web URL. You can do this using following code snippet:

        var hostweburl = getQueryStringParameter("SPHostUrl");
        var appweburl = getQueryStringParameter("SPAppWebUrl");
        hostweburl = decodeURIComponent(hostweburl);
        appweburl = decodeURIComponent(appweburl);

        function getQueryStringParameter(paramToRetrieve) {
                var params =
                    document.URL.split("?")[1].split("&");
                for (var i = 0; i < params.length; i = i + 1) {
                    var singleParam = params[i].split("=");
                    if (singleParam[0] == paramToRetrieve)
                        return singleParam[1];
                }
      }

Once you get host and app web URLs, next step is to load the ‘SP.RequestExecutor.js’ and ‘SP.Taxonomy.js’ libraries.  Following code snippet is useful:

            var scriptbase = hostweburl + "/_layouts/15/";
                                                                 $.getScript(scriptbase + "SP.Runtime.js",
                    function () {
                        $.getScript(scriptbase + "SP.js",
                        function () { $.getScript(scriptbase + "SP.RequestExecutor.js",
                                                                                                function () {
                                                                                                                $.getScript(scriptbase + "SP.Taxonomy.js", LoadData);
                                                                                                }
                                                                                                );}
                     );
                  }
             );

The Request Executor library(SP.RequestExecutor.js) enables cross-domain client-side calls, and ‘SP.Taxonomy.js’ is required to interact with managed metadata services. Once both are loaded you are ready to go to make calls for Taxonomies.

Load the Groups:

Now let’s see how to interact with taxonomy. You first needs to load the Taxonomy Session -> then get the term stores with this session -> then get the particular term store -> the load the group collection of term store. Following is the complete snippet to get the groups of term store.

function LoadData () {   
       context = new SP.ClientContext(appweburl);
        var factory =
            new SP.ProxyWebRequestExecutorFactory(
                appweburl
            );
        context.set_webRequestExecutorFactory(factory);
        appContextSite = new SP.AppContextSite(context, hostweburl);
        web = appContextSite.get_web();
        context.load(web);                
        taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
        termStores = taxSession.get_termStores();
        termStore = termStores.getById(termStoreID);
        context.load(termStore);
        termGroups = termStore.get_groups();
       context.load(termGroups);
        context.executeQueryAsync(onSuccess, onFail);
}
function onSuccess() {
        var termGroupEnumerator = termGroups.getEnumerator();
        groupsArr = new Array();
        //iterate through the enum and collect data in array - all groups of term store.
        while (termGroupEnumerator.moveNext()) {
                var group = termGroupEnumerator.get_current();                                         
                alert(“Label: ” + group.get_name() + "id: " + group.get_id());
                }
}
function onFail(sender, args) {
         alert( ‘Error’);
}

In this way you can get the groups of the term store, also you can get basic properties of the group.

Load the Term Sets

Once group is retrieved you can get the all term sets under the group. To get all term sets use following code snippet:

         taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
         termStores = taxSession.get_termStores();
         termStore = termStores.getById(termStoreID);
         termGroups = termStore.get_groups();
         var termGroup = termGroups.getById(id);
         termSets = termGroup.get_termSets();
         context.load(termSets);

        context.executeQueryAsync(function () {
                                                var termSetsEnumerator = termSets.getEnumerator();
                                                termSetsArr = new Array();
                                                while (termSetsEnumerator.moveNext()) {
                                                var termSet = termSetsEnumerator.get_current();                                         
                                                alert("label: " + termSet.get_name() +" id: " + termSet.get_id());
                                                }
        }
        , onFail);

Load the Terms within Term Set

You can get the all terms of a particular Term Set using following code snippet:

       taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
       termStores = taxSession.get_termStores();
       termStore = termStores.getById(termStoreID);
       termSet = termStore.getTermSet(id);
       termSets = termSet.get_terms();
       context.load(termSets);
       context.executeQueryAsync(function () {
                                                var termSetsEnumerator = termSets.getEnumerator();
                                                termSetsArr = new Array();
                                                while (termSetsEnumerator.moveNext()) {
                                                var termSet = termSetsEnumerator.get_current();                                         
                                                alert("label: " + termSet.get_name() +" id: " + termSet.get_id());
                                                }
        }
        , onFail);

Load the Terms within Term

Following code snippet fetches terms within any term, this is confusing statement but I have this one for now.

      taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
      termStores = taxSession.get_termStores();
      termStore = termStores.getById(termStoreID);
      term = termStore.getTerm(id);
      termSets = term.get_terms();
      context.load(termSets);
      context.executeQueryAsync(function () {
                                                var termSetsEnumerator = termSets.getEnumerator();
                                                termSetsArr = new Array();
                                                while (termSetsEnumerator.moveNext()) {
                                                var termSet = termSetsEnumerator.get_current(); 
                                                alert("label: " + termSet.get_name() +" id: " + termSet.get_id());
                                                }
        }
        , onFail);


Get the Details of Group

Following code snippet helps to get the details of group:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
termObject = termStore.getGroup(id);                
context.load(termObject);
context.executeQueryAsync(function () {
                var properties = termObject.get_objectData().get_properties();
                alert(properties.Id);
                alert(properties.Name);
                alert(properties.Description);                                   
                alert (properties.CreatedDate);
                alert (properties.LastModifiedDate);
                alert(properties.IsSiteCollectionGroup);
             alert(properties.IsSystemGroup);
                }
                , onFail);


Get the Details of Term Sets

Following code snippet helps to get the details of Term Sets:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
termObject = termStore.getTermSet(id);                            
context.load(termObject);
context.executeQueryAsync(function () {
                                                var properties = termObject.get_objectData().get_properties();
                                                alert(properties.Id);
                                                alert(properties.Name);
                                                alert(properties.Description);                                   
                                                alert(properties.CreatedDate);
                                                alert(properties.LastModifiedDate);                                      
                                                alert(properties.IsAvailableForTagging);
                                                alert(properties.IsOpenForTermCreation);
                                                alert(properties.Owner);
                                                alert(properties.Contact);
}
, onFail);

Get the Details of Term

Following code snippet helps to get the details of Term:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
termObject = termStore.getTerm(id);                   
context.load(termObject);

context.executeQueryAsync(function () {
                                                var properties = termObject.get_objectData().get_properties();
                                                alert(properties.Name);
                                                alert(properties.Id);
                                                alert(properties.Description);
                                               
                                                alert(properties.CreatedDate);
                                                alert(properties.LastModifiedDate);                                      
                                                alert(properties.IsAvailableForTagging);
                                                alert(properties.IsDeprecated);
                                                alert(properties.IsKeyword);
                                                alert(properties.IsPinned);                         
                                                alert(properties.IsPinnedRoot);
                                                alert(properties.IsReused);
                                                alert(properties.IsRoot);
                                                alert(properties.IsSourceTerm);
                                                alert(properties.Owner);
                                                alert(properties.PathOfTerm);
                                                alert(properties.TermsCount);                                 
                                }
                                , onFail);

Delete Group

Following code snippet helps to delete the group :

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var groupTodelete = termStore.getGroup(id);
groupTodelete.deleteObject();
context.executeQueryAsync(function () {
                alert("Removed Successfuly.");
},
onFail);

Delete Term Set

Following code snippet helps to delete the Term Set :

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var termSetTodelete = termStore.getTermSet(id);
termSetTodelete.deleteObject();           
context.executeQueryAsync(function () {
                alert("Removed Successfuly.");
},
onFail);

Delete Term

Following code snippet helps to delete the Term:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var termTodelete = termStore.getTerm(id);
termTodelete.deleteObject();
context.executeQueryAsync(function () {
                alert("Removed Successfuly.");
},
onFail);


Add New Term Set in Group

Following code snippet helps to add the group:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var group = termStore.getGroup(id);
var newTermSet = group.createTermSet(“termName”, newGuid.toString(),1033);
context.load(newTermSet);
context.executeQueryAsync(function () {
                alert("Done Successfuly.");
},
onFail);

Add New Term in Term Set

Following code snippet helps to add the Term Set:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var termSet = termStore.getTermSet(id);
var newTerm = termSet.createTerm(termName, 1033, newGuid.toString());
context.load(newTerm);
context.executeQueryAsync(function () {
                alert("Done Successfuly.");
},
onFail);
 

Add New Term under another Term

Following code snippet helps to add the Term:

taxSession = SP.Taxonomy.TaxonomySession.getTaxonomySession(context);
termStores = taxSession.get_termStores();
termStore = termStores.getById(termStoreID);
var parentTerm = termStore.getTerm(id);
var newCTerm = parentTerm.createTerm(termName, 1033, newGuid.toString());
context.load(newCTerm);
context.executeQueryAsync(function () {
                alert("Done Successfuly.");
},
onFail);


In this way you can perform those activities with the term store in SharePoint App using ECMA scripting.

Wednesday, April 1, 2015


This is a special post on the request from many of my friends and followers. Everyone wants to know which is the best approach to integrate Yammer in SharePoint. Yammer has provided multiple options to integrate Yammer in SharePoint, one thing I would like to clear here is that you can combine any of them or all of them to full fill your requirements. There is really not any hard rule when to use which option, here what I am going to share is all depends on my past experience of Yammer integration. With some of my approaches you may disagree, but that's all we have for now.

Lets start with understanding each option and its advantages and disadvantages.

1. Yammer web part:

             This is simple way, all you need is deployment of yammer web part solutions on your farm. Remember it requires farm deployment. After deployment you need to enable Yammer features of web part and configure web part on required page.

Advantages:

1. Simple to configure.
2. Install one time, use many time.

Dis-Advantages:

1. It requires farm deployment.
2. No way for branding as per the branding site have.
3. No way to customize the feeds.

This approach was originally for SharePoint 2010. It does works for SharePoint 2013 on premise.

Some points you need to remember about web part while designing are:

1. It requires farm deployment so not a option for SharePoint online.
2. The web part doesn't have RWD design so cannot work on mobile devices.
3. You cannot show feeds as per your wish.

2. Yammer embedded:

This is another simple approach to integrate Yammer feeds in SharePoint site. Alongside feeds you can do other actions: like , follow a specific page, etc. Find some of the implementation example of embed here.

Advantages:

1. Simple to configure.
2. Its plug and play. It will work on any web site.
3. Can be placed multiple times on same page. Advantage over Web part.
4. No need of any deployment.

Dis-Advantages:

1. Does not support RWD structure.
2. Little scope for branding.
3. Lightweight but slower.

Some points you need to remember while designing:

1. They don't need any farm deployment.
2. Easy placement on pages most time its manual work.
3. Does not have RWD enabled so incompatible to small mobile devices.
4. Little chances to customize as per branding.


3. Yammer App:

Yammer App has been introduced in SharePoint 2013; this is free App. This is great option for SharePoint online. This is very much similar to Yammer  web part. App settings are simple and very similar to the Web part. Though its similar to the Yammer web part it has limited options than web part. To use this on On premise, you need to do setup for App catalog.

Advantages:

1. Easy to install and configure.
2. No need of any deployment on farm.

Dis-Advantages:

1. Minimum provision to change look and feel as well as some functions.
2. Limited feed options.
3. Cannot follow site's branding.

To use on on-premise SharePoint, it needs to setup App Catalog.

4. Yammer REST:

All above integration approaches are available ready made. All of them have a disadvantage that you can not do implementation as per your requirement. Things like applying theme, styles, adding or removing certain features not available in above options. There is little scope for customization in above approaches.

In case of custom development of yammer components you need to use the REST services provided by Yammer. There are various REST services available and covers almost all features of Yammer. Using REST services one can interact with Yammer for  messages, user information, groups, networks and other activities like - follow, like, etc.

Following URL has list of all available REST services. This also contains the SDK for JavaScript.
While developing custom components using REST API you need use this SDK which makes life little bit easier.

https://developer.yammer.com/v1.0/docs/rest-api-rate-limits 

Advantages:

1. Custom component development is possible.
2. Applying Theme, styles possible.
3. Easy to use.
4. Development of reporting component is possible.
5. It is possible to create a component which can support all devices and browsers.

Dis-Advantages:

1. It involves development time and cost.
2. Not all API present at the moment.
3. Microsoft keep changing the API library.

With this much description I  think it is clear to you that which would be best approach for you while Yammer integration with Yammer. Each method has pros and cons; its you who needs to choose the best suitable way for integration. If you still have queries on this then please send a mail so I can help you over finalizing approach.

Happy Yamming!


In previous article we saw how to get attachments of the list items using SharePoint 2013 REST services. Now in this article we will see how to upload the file as an attachment to the list item.

Following is the SharePoint 2013 REST service to add or upload attachments:

/_api/web/lists/getbytitle('testlist')/items(1)/AttachmentFiles/ add(FileName='" + fileName + "')

You just need to provide item id to which you want to attach file and attachment file name. Rest of the things are similar to how to upload the file.

Following is the complete code to upload the attachments:

<html>
<head>
<script src="/Site%20Assets/js/jquery-1.11.1.min.js"></script>
<script>
function AddAttachments()
{
var digest = "";
$.ajax(
{
                url: "/_api/contextinfo",
                method: "POST",
                headers: {
                                "ACCEPT": "application/json;odata=verbose",
                                "content-type": "application/json;odata=verbose"
                },
                success: function (data) {
                digest = data.d.GetContextWebInformation.FormDigestValue;
                },
                error: function (data) {
                               
                }
}).done(function() {
                var fileInput = $('#uploadFile');
                var fileName = fileInput[0].files[0].name;
                var reader = new FileReader();
                reader.onload = function (e) {
                var fileData = e.target.result;
                                var res11 = $.ajax(
                                {                             
                                                url: "/_api/web/lists/getbytitle('testlist')/items(1)/AttachmentFiles/ add(FileName='" + fileName + "')",                                       
                                                method: "POST",
                                                binaryStringRequestBody: true,
                                                data: fileData,
                                                processData: false,
                                                headers: {
                                                                "ACCEPT": "application/json;odata=verbose",                                                                                                                                   
                                                                "X-RequestDigest": digest,
                                                                "content-length": fileData.byteLength
                                                },                                                                                                                            
                                                success: function (data) {                                            
                                                                                                               
                                                },
                                                error: function (data) {
                                                                alert("Error occured." + data.responseText);
                                                }
                                });                          
                };
                reader.readAsArrayBuffer(fileInput[0].files[0]);

});                                          
}
</script>
</head>
<body>
<div>
                <input id="uploadFile" type="file">
</div>

<div>
                <input type="submit" onclick="AddAttachments()" value="Add Attachments"> </input>
</div>
</body>
</html>

Happy SharePoint coding.

In previous few articles we saw how to work with files and folders in the documents library using SharePoint 2013 REST services. Now lets see how to work with attachments of list items using SharePoint 2013 REST services. They are also important part of the SharePoint list. So SharePoint has given necessary APIs to interact with attachments. In this article we will see how to get attachments of list item.

Following is the REST URL to get all attachments:

/_api/web/lists/getbytitle([List Title])/items(1)/AttachmentFiles/

In response you will get all details of file as well as the URL of file.

Following is the sample code snippet to get all attachments:

<html>
<head>
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<script src="/Site%20Assets/js/jquery-1.11.1.min.js"></script>
<script>
function GetAllAttachments()
{
                $.ajax(
                {
                url: "/_api/web/lists/getbytitle('testlist')/items(1)/AttachmentFiles/",  
                method: "GET",
                headers: {
                                "ACCEPT": "application/json;odata=verbose",
                                "content-type": "application/json;odata=verbose"                         
                },
                success: function (data) {
                                var htmlStr = "";
                                $.each(data.d.results, function(){
                               
                                                if(htmlStr === "")
                                                {
                                                                htmlStr = "<li 'ServerRelativeUrl="+ this.ServerRelativeUrl + "'>"  + this.FileName + "</li>";
                                                }
                                                else
                                                {
                                                                htmlStr = htmlStr + "<li 'ServerRelativeUrl="+ this.ServerRelativeUrl + "'>"  + this.FileName + "</li>";
                                                }
                               
                                });
                               
                                $("#foldersDiv").html(htmlStr);
                },
                error: function (data) {
                                alert("Error occured." + data);
                }
});          
                                               
}

</script>

</head>
<body>
<div>
                <input type="submit" onclick="GetAllAttachments()" value="Get All Attachments"> </input>
</div>

<div>
                <ul id="foldersDiv">
                </ul>
               
</div>
</body>
</html>

Happy SharePoint coding.

In last article we saw how to check out file, now in this article we will see how to check in the file using SharePoint 2013 REST services. Check in is an important operation. Once you have done with the changes in the file you must check in it so othr can access the latest version and work on it.

Following is the REST service to check in the file:

/_api/web/GetFileByServerRelativeUrl('[File server relative url]')/CheckIn(comment='this is test comment', checkintype=0)

You need to pass two parameters:

1. comment: Give some comments about your check in operation.
2. checkintype : This is type of check in for file.

MinorCheckIn = 0.

MajorCheckIn = 1.

OverwriteCheckIn = 2.

Following is the complete code to check in the file:

<html>
<head>
<script src="/Site%20Assets/js/jquery-1.11.1.min.js"></script>
<script>

function CheckInFile()
{
var digest = "";
$.ajax(
{
                url: "/_api/contextinfo",
                method: "POST",
                headers: {
                                "ACCEPT": "application/json;odata=verbose",
                                "content-type": "application/json;odata=verbose"
                },
                success: function (data) {
                digest = data.d.GetContextWebInformation.FormDigestValue;
                },
                error: function (data) {                               
                }
}).done(function() {
                                $.ajax(
                                {                                             
                                                url: "/_api/web/GetFileByServerRelativeUrl('/test/folder1/test1.doc')/CheckIn(comment='this is test comment', checkintype=0)",
                                                method: "POST",                                            
                                                headers: {
                                                                "ACCEPT": "application/json;odata=verbose",                                                                                                                                   
                                                                "X-RequestDigest": digest
                                                },                                                                                                                            
                                                success: function (data) {                                            
                                                                alert("Checked In");                                      
                                                },
                                                error: function (data) {
                                                                alert("Error occured." + data.responseText);
                                                }
                                });                          
                });                                
}

</script>
</head>
<body>
<div>
                <input type="submit" onclick="CheckInFile()" value="Check in File"> </input>
</div>
</body>

</html>

Happy SharePoint coding.