Saturday, December 17, 2016

How to get more items than threshold limit from SharePoint 2013/Online using REST API

While working with SharePoint, we always get stuck with the condition of not able to fetch more than threshold items(which is 5000 items per query). I have found a very easier way to get all item from a list into memory and the use it for binding, comparing or any other purpose, we want to use it for. Here my approach would be keep querying list till the time I am getting count equal to current threshold value.

 var fields = []; //All fields internal names
var expand = []; //Fields name to expand
var listName = string; // List title goes here
var listTemplate = []; // All records goes here, needs to be global
var ItemIDs = []; //An aarey to store Ids, needs to be global
function loadListData() {
   var ID = 0;
if(ItemIDs.length > 0)
    ID = ItemIDs[ItemIDs.length - 1];
$http({
method: "GET",
url: siteUrl + "/_api/web/lists/getByTitle('" + listName + "')/items()/"
+ "?$select=ID, " + fields
+ "&$expand=" + expand
+ "&$filter=ID gt "+ ID
+ "&$orderby=ID asc"
+ "&$top=5000", // SP limit is 100 by default
headers: { "Accept": "application/json;odata=verbose" }
}).success(function(data, status, headers, config) {
listTemplate = listTemplate.concat(data.d.results);
ItemIDs = ItemIDs.concat(data.d.results.map(function(v){ return (v.ID); }));
if(data.d.results.length == 5000) {
loadListData();
}
else {
   alert("Total records got from list are: " + ItemIDs.length);
//Next Function you want to execute after getting all records from list.
}
}).error(function (data, status, headers, config) {
 alert("Error while fetching data from list: "+ listName):
});
};

Just include this function with keeping these variables in global scope. Please let me know for any assistance or issues you face around it.

Friday, December 16, 2016

Get details of each user in SharePoint Site using ECMA Script

As you all are aware how tedious its to add find out details of each user into a SharePoint site.
There are only two ways for it first one is going to check permission option in site collection and then checking for each user one by one. Another option would be to get into each group ad then search for them.
To get rid of such time consuming process for users having no access to server, I have created a small piece of code script for getting details for all users using Client Side coding:

<html>
<head>
<script src="//code.jquery.com/jquery-1.12.3.js" type="text/javascript"></script>
<script src="https://cdn.datatables.net/1.10.12/js/jquery.dataTables.min.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css" /> 
<script type="text/javascript">
$(document).ready(function() {
    
} );
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', GetAllUsersInCurrentSite);
var groupUserMapping = [];
var AllUsersInSite = [];

    function GetAllUsersInCurrentSite() {
alert("Hi..");
var clientContext  = SP.ClientContext.get_current();
collGroup = clientContext.get_web().get_siteGroups();
clientContext.load(collGroup);
clientContext.load(collGroup, 'Include(Users)');
clientContext.executeQueryAsync(onQuerySucceeded,function() {});
}

function onQuerySucceeded(sender, args) {
var userInfo = '', groupInfo = '';
var groupEnumerator = collGroup.getEnumerator();
while (groupEnumerator.moveNext()) {
var oGroup = groupEnumerator.get_current();
var collUser = oGroup.get_users();
var userEnumerator = collUser.getEnumerator();
while (userEnumerator.moveNext()) {
  var oUser = userEnumerator.get_current();
  AllUsersInSite.push(oUser.get_id());
  groupUserMapping.push({GroupTitle: oGroup.get_title(), UserLoginName: oUser.get_loginName(), UserId: oUser.get_id(), UserTitle: oUser.get_title()});
}
}
var AllUniqueUserIds = AllUsersInSite.unique();
var Contacts = [];
AllUniqueUserIds.forEach(function(x){
var y =[];
var UserTitle = LoginName = '';
y["ID"] = x;
var groupVal = groupcount = '';
var groupMatch = groupUserMapping.filter(function (el) {
 return el.UserId == x;
});
if(groupMatch && groupMatch.length > 0) {
groupMatch.forEach(function(val){
groupVal += val.GroupTitle +", ";
UserTitle = val.UserTitle;
LoginName = val.UserLoginName;
groupcount = groupMatch.length;
});
}
y['UserName'] = UserTitle;
y['LoginName'] = LoginName;
y['GroupDetails'] = groupVal;
y['GroupCount'] = groupcount; 
Contacts.push(y);
});

$('#example').DataTable( {
        data: Contacts,
        columns: [
            { data: "UserName", title: "User Name"  },
            { data: "LoginName", title: "Login Name" },
            { data: "GroupDetails", title: "Group Names" },
{ data: "GroupCount", title: "Group Count" }
        ]
} );

}

Array.prototype.contains = function(v) {
    for(var i = 0; i < this.length; i++) {
        if(this[i] === v) return true;
    }
    return false;
};

Array.prototype.unique = function() {
    var arr = [];
    for(var i = 0; i < this.length; i++) {
        if(!arr.contains(this[i])) {
            arr.push(this[i]);
        }
    }
    return arr; 
}
if (!Array.prototype.filter) {
Array.prototype.filter = function(fun /*, thisp*/) {
    var len = this.length >>> 0;
    if (typeof fun != "function")
    throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this) {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
        res.push(val);
      }
    }
    return res;
  };
}
</script>
</head>
<body>
<table id="example" class="display" width="100%"></table>
</body>
</html>

Just need to make sure that you have access to internet as I am referring JQuery and Data table CDN. As soon you add this HTML file into a SharePoint Page CEWP. You would be able to see the details of each user, group names- user is part of, group count as below screenshot.



I have filtered it my name just to show my own membership with few generic groups. :)

Also just add reference to table export library and code to export this table into excel:

$("table[id='example']").tableExport({
headings: true,                    // (Boolean), display table headings (th/td elements) in the <thead>
footers: true,                     // (Boolean), display table footers (th/td elements) in the <tfoot>
formats: ["xlsx"],    // (String[]), filetypes for the export
fileName: "id",                    // (id, String), filename for the downloaded file
bootstrap: true,                   // (Boolean), style buttons using bootstrap
position: "bottom" ,                // (top, bottom), position of the caption element relative to table
ignoreRows: null,                  // (Number, Number[]), row indices to exclude from the exported file
ignoreCols: null ,                  // (Number, Number[]), column indices to exclude from the exported file
ignoreCSS: ".tableexport-ignore"   // (selector, selector[]), selector(s) to exclude from the exported file
});

We can also extend above functions to get details regarding users. Hope it helps someone.!