Listing Marked Documents from Multiple Document Libraries – Part 1

I had a small project at work to list marked documents a SharePoint site Page. The documents would be part of a Document Library and they are marked using a choice option, which means they need to be grouped by each of the options in the list. And, to top things off, there are multiple Document Library lists. And, to make things harder, the choice field has a different name in each of the Document Library list. At first, I thought this might be a hard little project, but it turned out easier to do than expected.

I am using the REST API for SharePoint to get the data I need for displaying.

Since the display of the files is first grouped by each of the Document Library lists, the first step is to get those list names and such. This might have been a daunting task, if it hadn’t been for using “BaseTemplate” in the REST filter call.

$filter=BaseTemplate eq 101

Using the SPListTemplateType enumeration you can filter the lists (sorry Microsoft, they are still lists, even according to your documentation) using a enumeration value. Using 101 gives me only the Document Library lists. However, I also want to reduce the number of Document Library lists to only the ones that have files in them. Doing this removes having a bunch of headers without anything in them and of course, it would reduce the REST call and the data returned. Simple enough, using “ItemCount” gives me the number of files in the Document Library and setting the filter to make sure there are more than files than 0 is straight forward.

$filter=ItemCount eq 0

Now, I need to put those two filters together and that can be done with a the operator “and” between the two filter statements. NOTE: I found that on some help sites, the operators were listed with a capital letter, i.e Lt Gt Eq Neq, but the REST API does not like that, nor a uppercase operator. So, keep it all lower case. To make things orderly, I also added an orderby option to the Document Library name field which is “EntityTypeName”

/_api/web/lists?$filter=BaseTemplate eq 101 and ItemCount gt 0&$orderby=EntityTypeName

Next, I need to get the name of the column for the choice list for each Document Library. While each column name is different, they do have a similar value at the start of the name, which makes things easy. But, before I can filter out those I have to see the Fields, which requires an option called “expand“. By expanding the Fields, I can get back more information in the data, including the column names.

$expand=Fields

When the data (OData) is returned, for each row, I can go into the Fields data and find the column that starts with a certain value (hoping that someone didn’t name two fields with the same starting value), which can be found using “startsWith”.

$(this.Fields.results).each( function() {
if(this.Title.startsWith("Key")) {
keyField = this.InternalName;
}
});

Having retrieved the Document Library Id, Title and the keyField for each, I put them in an array in order to start building the display and to get the file list for each Document Library.

For the display, I decided to create holder DIVs that I can call later. Simply enough, I use the EntityTypeName, which is the Title without spaces, to create a unique ID for each div.

items2.push('
<div id="' + this.EntityTypeName + '">
' 
	+ '
<h2><nobr><span>' +  this.Title + '</span></nobr></h2>

 \n'
	+ '
<div id="' + this.EntityTypeName + 'Holder"></div>

 \n'
	+ '</div>

 \n');

As you might guess, I am creating multiple arrays. The reason I am doing this, is because the project asked for the lists to be displayed in two columns on the page. I use a odd or even check to split the lists into the two different arrays. Then I create two overall holder DIVs with less than 50% width and float them left and right. Finally, I update the HTML in those DIVs with the array values, which creates the holder DIVs for each Document Library set.

This is the entire code for everything created so far, which I call after the page body has loaded and the site URL is found. I needed to find the site URL, because this page will be put on multiple sites.

function getLibraries() {
	$.ajax({
	   // get lists where list type is 101 (Document Library) and the ItemCount in that list is great than 0
	   url: siteURL + "/_api/web/lists?$filter=BaseTemplate eq 101 and ItemCount gt 0&$select=Id,Title,ItemCount,EntityTypeName,Fields&$expand=Fields&$orderby=EntityTypeName", //THE ENDPOINT
	   method: "GET",
	   headers: { "Accept": "application/json; odata=verbose" },
	   success: function (data) {
	        //console.info(data);
	        var items1 = [];
	        var items2 = [];
	        var splitItems = false;
	        $(data.d.results).each( function(index) {
	        		// check to see if results are greater than 1
	        		if(data.d.results.length > 1) {
	        			//create two holders and set to alternate items
	        			splitItems = true;
	        			$("#listResult").html('
<div id="groupOne" style="float:left; width:48%; vertical-align:text-top;"></div>

'
	        				+ '
<div id="groupTwo" style="float:right; width:48%; vertical-align:text-top;"></div>

'
	        			);
	        		} 
	        		// get the key field by finding the column that starts with "Key"
	        		var keyField = '';
	        		$(this.Fields.results).each( function() {
	        				if(this.Title.startsWith("Key")) {
	        					keyField = this.InternalName;
	        				}
	        		} );
	        		// build libraryList array
	        		libraryList.push([this.Id, this.EntityTypeName, this.Title, keyField]);
	        		// build display array, to create div holders for each Discipline Library
	        		if(splitItems) {
	        			if(index % 2) {
	        				items2.push('
<div id="' + this.EntityTypeName + '">
' 
			        		+	'
<h2><nobr><span>' +  this.Title + '</span></nobr></h2>

 \n'
			        		+	'
<div id="' + this.EntityTypeName + 'Holder"></div>

 \n'
			        		+ '</div>

 \n');
	        			} else {
	        				items1.push('
<div id="' + this.EntityTypeName + '">
' 
			        		+	'
<h2><nobr><span>' +  this.Title + '</span></nobr></h2>

 \n'
			        		+	'
<div id="' + this.EntityTypeName + 'Holder"></div>

 \n'
			        		+ '</div>

 \n');
	        			}
	        		} else {
	        			items1.push('
<div id="' + this.EntityTypeName + '">
' 
		        		+	'
<h2><nobr><span>' +  this.Title + '</span></nobr></h2>

 \n'
		        		+	'
<div id="' + this.EntityTypeName + 'Holder"></div>

 \n'
		        		+ '</div>

 \n');
	        		}

	        });
	        // output display
	        if(splitItems) {
	        	$("#groupOne").html(items1.join(''));
	        	$("#groupTwo").html(items2.join(''));
	        } else {
	        	$("#listResult").html(items1.join(''));
	        }
	        // call the function to retrieve and populate the list items
	        getLists();
	   },
	   error: function (data) {
	  		console.info("There was an error retrieving the Document Library list.");
	  		console.info(data);
		 }
	});
}

On to Part 2

About DeanLogic
Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.

About DeanLogic

Dean has been playing around with programming ever since his family got an IBM PC back in the early 80's. Things have changed since BASICA and Dean has dabbled in HTML, JavaScript, Action Script, Flex, Flash, PHP, C#, C++, J2ME and SQL. On this site Dean likes to share his adventures in coding. And since programming isn't enough of a time killer, Dean has also picked up the hobby of short film creation.