Archive for April, 2016

Create a List of SharePoint Views Using REST

My client has a sub site that has the sole purpose of housing their policy documents.  They don’t want any other team site features on this site, just the library.  The library contains a couple thousand documents all nicely categorized using metadata and organized by views.  A recent request from them was to clear their site’s landing page of the default web parts and replace it with a list of the views.  Each view in the list should link directly to that view in the library.  To facilitate their request I decided to create a list of SharePoint views using REST services.

Choosing a Method

A number of methods are available for us to accomplish this:

  1. Server-side Web Part: Bad.  Don’t do this anymore.  Stay as far away from server side code as much as possible.  This is a discussion for another day and there are lots of resources out there outlining why we shouldn’t, but suffice to say, don’t do it.
  2. CSOM Add-In: This is a strong possibility and one that is generally used, but we have developed a policy to avoid CSOM solutions because it still requires assemblies that have to be maintained
  3. JSOM Add-In: This method is perfectly fine and something available to any SharePoint solution.  It would suffice for my needs.  I just chose a different method.
  4. JavaScript and REST: I chose this method not because it is better than any of the others listed, but simply because my need was very basic and I didn’t need to build out a full solution to achieve my requirements.  I could create my solution using a Content Editor Web Part (CEWP) and a single JavaScript file (well two because I used JQuery as well).

Create a List of SharePoint Views Using REST

The solution is pretty straight forward and uses very little custom code.  The gist of the solution is removing all the web parts from the page.  Adding the CEWP to the page.  Uploading JQuery and my custom code file to Site Assets and referencing them from within the CEWP.

ListCollection REST Endpoint

To get the data from the list we need to make use of the ListCollection resource.  A method within the resource allows us to access a list within by it’s name.  So your REST call will have a base something like: “/<Site Name >/_api/web/lists/getbytitle(<List Title>)”  So this gives us the list object.  Instead of using the return data from SharePoint on this, we are able to tell the call that we want the views property within.  So in the end our REST call is going to be http://teams.drevsp2013.com/bcs/_api/web/lists/getbytitle(‘Laptop Request Form’)/Views

Because it is so easy to work with we of course want to ensure we tell the service call we would like the results in JSON format.  So we need to add an accept to the header “accept: application/json;odata=verbose

Test with Fiddler

When checking out any REST endpoint I always use Fiddler.  Two reasons:

  1. Ensure I format my REST call correctly
  2. Take a look at how the data is coming back so I know how to handle it in code

Setup and execute a Fiddler test as follows:

Create a List of SharePoint Views Using REST - FiddlerCall

Taking a look at the JSON return, we see that we want to make use of the Title and the ServerRelativeUrl fields:

Create a List of SharePoint Views Using REST - Fiddler REST Return

Create the REST Call

So building out this knowledge I wrote a little method called GetViewDetails.  It accesses the REST endpoint and builds an associative array (I’ll explain why in a minute) to store the title and URL of the views.

function GetViewDetails(siteName, listName){
    var restURL = "/" + siteName + "/_api/web/lists/getbytitle('" + listName + "')/views";
    var viewArray = [];
    
    //Call the list API and gather information on all the views.
    $.ajax({        
        url:restURL,
        type:"GET",
        headers: {"accept": "application/json;odata=verbose"},
        async: false,
        success: function(data){
            $.each(data.d.results, function(index, item){
                //Need to ignore the All Documents and the hidden views:
                if(item.Title != "All Documents" && item.Title != "Merge Documents" && item.Title != "Relink Documents" && item.Title != "assetLibTemp")
                {
                    //build the associative array
                    viewArray[item.Title] = item.ServerRelativeUrl;                   
                }
            });
        },
        error: function(error){
            $('#DisplayViews').append("<p>An Error occurred building list of policy groups. Error received: " + JSON.stringify(error) + "  Please contact the service desk");
        }
    });     
    
    return viewArray;
}

Because the client only wanted their custom views I do not add All Documents or the internal hidden views to the array.  Also note that I do not want this to be called asynchronously.  Reason being is I am building out that array and I want to be able to return the values.  If I don’t do this, it will return the data before the array is built.

Another requirement is to place all the views in alphabetical order.  The REST service doesn’t do that by default.  It actually returns the views in the order they were created.  Enter the Associative Array.  The associative array in Javascript is a Key\Value based array.  So basically a dictionary or hashtable.  By placing my data into this array I can sort the data on the key (view title) portion of the array.  Before I show you that part, I am going to first add the necessary code to my CEWP as I make reference to some HTML in the web part within the next method.

After you add the CEWP, edit the source of the web parts content.  Inside the HTML we are going to add the a div that our code can hook into and the script calls for the JS files.

Create a List of SharePoint Views Using REST - DIVInCEWP

So back to the JavaScript.  The final piece to write is the portion that sorts the array and writes to the CEWP.  The code to handle this:

function displaySortedViews(viewArray) {              
    //sort the array keys
    var sortedKeys = Object.keys(viewArray).sort();
    
    //create an unordered list on the page
    $('#DisplayViews').append("<ul id='viewList'></ul>");
    
    //loop through each view and add to the page.
    for(var i=0; i < sortedKeys.length; i++)            
    {
        $('#viewList').append("<li> <a href='" + viewArray[sortedKeys[i]] + "'>" + sortedKeys[i] + "</a></li>");
    }
}

In the code above, it sorts the key values of the array and places them into a new variable.  We then use that order to loop through every item in the array and display them as needed.  viewArray[sortedKeys[i]] is basically saying give me the value of the array when the key is equal to the value at ‘i’.  We then attach to the un-ordered list created before the loop and for each entry in the array we add a list item to the un-ordered list.

So what we end up with is a list of links that correspond to each view and the url of the view.

Create a List of SharePoint Views Using REST - List of Views

 

The final JavaScript file looks like this:

/**********************************************************************************************
* Title: createViewLinks.js                                                                   *
*                                                                                             *
* Date             Who             Comments                                                   *
* April 28, 2016   David Drever    Created to gather the views and their URLS in a            *
*                                  library and build a list to directly link to               *
*                                  them                                                       *
***********************************************************************************************/

$(document).ready( function() { 
    var siteName = "bcs";
    var listName = "Laptop Request Form";   
    var arrayViews = GetViewDetails(siteName, listName);
    displaySortedViews(arrayViews);
});


/**********************************************************************************************
*Function Name: GetViewDetails              												  *
*Parameters: siteName - URL Sitename of site we are accessing data from 				      *
*            listName - Name of the list to access                 							  *
*			                                 												  *
*Return Value: Returns associative array containing Item Title (key) and URL (Value)          *
*Purpose: Accesses the list's view endpoint to gather data on each view within the list       *
***********************************************************************************************
*/
function GetViewDetails(siteName, listName){
    var restURL = "/" + siteName + "/_api/web/lists/getbytitle('" + listName + "')/views";
    var viewArray = [];
    
    //Call the list API and gather information on all the views.
    $.ajax({        
        url:restURL,
        type:"GET",
        headers: {"accept": "application/json;odata=verbose"},
        async: false,
        success: function(data){
            $.each(data.d.results, function(index, item){
                //Need to ignore the All Documents and the hidden views:
                if(item.Title != "All Documents" && item.Title != "Merge Documents" && item.Title != "Relink Documents" && item.Title != "assetLibTemp")
                {
                    //build the associative array
                    viewArray[item.Title] = item.ServerRelativeUrl;                   
                }
            });
        },
        error: function(error){
            $('#DisplayViews').append("<p>An Error occurred building list of policy groups. Error received: " + JSON.stringify(error) + "  Please contact the service desk");
        }
    });     
    
    return viewArray;
}


/**********************************************************************************************
*Function Name: displaySortedViews             												  *
*Parameters: viewArray - Associative array of view title\URLs            				      *
*			                                 												  *
*Return Value: None                                                                           *
*Purpose: Sorts list of views and displays to page                                            *
***********************************************************************************************
*/
function displaySortedViews(viewArray) {              
    //sort the array keys
    var sortedKeys = Object.keys(viewArray).sort();
    
    //create an unordered list on the page
    $('#DisplayViews').append("<ul id='viewList'></ul>");
    
    //loop through each view and add to the page.
    for(var i=0; i < sortedKeys.length; i++)            
    {
        $('#viewList').append("<li> <a href='" + viewArray[sortedKeys[i]] + "'>" + sortedKeys[i] + "</a></li>");
    }
}

 

Thanks for reading!!

How to Setup SharePoint Search to Crawl External Content With BCS

So the other day I wrote about an error received when your security is not setup properly when configuring search for external data using Business Connectivity Services.  I thought today would be a good day to show you how to setup SharePoint search to crawl external content with BCS.  Setting up search isn’t actually too hard once the ECT is there.  What people initially forget though is setting up the profile page.  This is what tells SharePoint how to display the data to you.  If you don’t setup profiles here is what things look like:

BCS Search With No Profile Configured

We can see from the link details that it is coming from the BDC (Business Data Connectivity).  That’s the service in SharePoint that houses BCS.  Clicking on the link just takes us back to the search center.  This is because SharePoint doesn’t know how to display the data to us.

Read more

SharePoint Search – Error While Crawling LOB Contents

Recently I was configuring search to access my SQL Server data via an external content type for a demo I was presenting.  Once the content source was configured I ran the full crawl to populate the index with the data from my external source.  After about a minute the crawl was marked complete.  So naturally I am going to want to test it and make sure my data is pulling through.  The external data is a basic asset database so I did a search for one of the manufacturers I knew was in there.  Received the dreaded “Nothing here matches your search” message.

SearchNoData

Well I know there is data in there so obviously something went wrong.  I know what is wrong as I have done this before, but I want to go through some of the troubleshooting steps you can do to help determine the problem.

Read more

Let’s Do Away with Best Practices

Wait! Before you call out the angry mob with the torches and pitch forks allow me to explain:

bring_all_the_pitchforks

I think the concept of best practices is absolutely fantastic.  It allows members of different communities (IT or other) to find out what is considered the best way to perform a task.  Whether that task is to create a form letter informing users of an opportunity or building a SharePoint environment (*ahem*, like this one), knowing the best methods to accomplish that need is extremely important, so no, I am not against best practices.  I am actually against the term\phrase “Best Practice”

Away With Best Practices

I hope the pitchforks have been put away and the torches doused.  Let me explain a bit further.  Bear with me as I freely admit that this is completely subjective.  The problem I have with the term best practice is in what it implies.  When you think of the word “best”, what comes to mind?  For me it is this is the highest level we can achieve.  This is the only way that we should do it and nothing else can replace it.  And there-in lies the problem.  If it is the only way something should be done ever, how can we improve?  In IT we know the best way to do something changes constantly.  Sometimes within days (a bit extreme I know, but it has been known to happen).

Let’s add a bit to this.  Another common thing heard is “current best practice”.  So if it is current, then that means it is expected to change. But if it is the best; how can it change?  See where I am going with this?

What Should We Use Instead?

I am not a word smith.  I spend most of my day writing code or configuring systems to make a user’s experience better.  However, since I have brought this up I should at least provide a suggestion of an alternative.  I personally prefer something like Leading Practice.  To me this implies, this is the way things should be done now, but there are also other great ways to do it or with time better ways could be found.  It encourages people to think, “this is good, but perhaps there is a better way”.  It doesn’t encourage people to think it shouldn’t be used.  To me it instills a sense of confidence in the method without causing people to believe it will always be the only way.

Let me know in the comments what you think?  Do you agree?  Am I out to lunch?  Do you have a suggestion for a descriptive phrase besides Leading Practices?

 

Thanks for reading!