How to make a SharePoint List work with Bootstrap – using SPServices and jQuery

For those of you who have worked with SharePoint in the past, particularly with lists, CEWPs (Content Editor Web Part) and front end code, then you probably know that these lists do not work well in mobile. The markup is just too messy – invalid tags, divs inside spans, inline Javascripts, inline styles and even tables! So it’s no surprise that making SharePoint work with Bootstrap is not an easy task.

In this post, I will show you how to use a Javascript plugin that I’ve written to basically recreate the markup of these SP lists so it works with Bootstrap / Mobile. It also has extra functionality like paging, filters, expand/collapse and other options. By the time we’re done, your list will look real good in desktop, tablet and mobile view:

View in Github

How to use the Plugin:

Note that I’ve only tested this with SharePoint 2013. You may need administrator rights to your website, as well as you should know how to work with custom lists and document libraries and such.

After you have downloaded the files, open the “sp-bootstrap-list-viewer.html” in you text editor. This is where you will add the plugin information. You basically need to add 2 things: the list name, the “Answer” column. The rest of the options are optional such as the “filterBy” and “rowLimit”. The table below will show you want the rest of the options do.

sp-list1

Once you have edited the html file, upload it to a location in your SharePoint site, typically a document library. You will need to copy the location of the file.

sp-list1

Let’s go ahead and add a CEWP into your SharePoint page. in the “Content Link” input, add the location of the html file you’ve just uploaded.

sp-list1

Click “OK” and if everything is configured correctly, you should see the plugin do its thing:

sp-bootstrap-list-viewer

The table below contains the options for the plugin and an explanation of what they’re for:

Option name Default Value Required? Description
instance Random Value Yes Used as the “Id” of your plugin
listName none Yes Name of the SP list
question Title Yes Title of the row
answer none Yes Body of the row
filterBy none No Category column to filter rows
rowLimit 5 No Number of rows to show

One thing to remember. If you plan to use the plugin multiple times in a page, you need to change the “instance” value to a random number prefixed with alphanumeric characters. You also need to make this the “Object” name of your html (where it says var spBL233565656 = new spBootstrapList …). This will make the instances of your plugin unique in every page and will not clash with each other.

Under the hood:

For those of you who want to know more about how the plugin works, I will show you some of it’s main functionality. Note that this was originally built for a FAQ list for SharePoint, hence the FAQ names such as “Question” and “Answer”. Though the plugin will work with any kind of SP list.

Requirements

We will need some help with Mark Anderson’s SPServices – a jQuery plugin that basically does the web service calls for us. This allows us to work with the lists’ data and convert it to our desired markup. Of course we will need Bootstrap – which will take care of the responsive and overall styles, as well as jQuery for DOM manipulation.

Notice the required scripts and styles. You can link to them externally or download them to a document library in SharePoint. Our constructor spBootstrapList() calls our Javascript class, passing along our required arguments. Again, the variable name “spBL233565656” and the value for “instance” has to be identical. This is for using it multiple of these in a single page.

So going into the Javascript plugin: sp-bootstrap-list-viewer.js, you will see that on first load there’s a public method that gets called to set things up “init()”. This makes the initial call to the plugin “SPServices”. As I’ve mentioned, the plugin does the AJAX call to the SharePoint web service. It uses SOAP as its protocol so the request / response will be in XML format. Our init() method also checks for valid fields:

Then we parse our response and we fill our internal object “_faqs”: Notice the SharePoint internal list names that start with “ows_” – these are how it comes out of the SOAP response. We parse it to our own object with more meaningful keys and it’s values:

By the way, in order for us to make public methods from within our plugin is that we assign it to the “this” keyword. This way it becomes accessible from the outside. Here is an example of all the public methods of our plugin:

Continuing with our process, note that we need the “_faq” array to be filled for our next method to fire. This method is called methods.buildFaqs(), So we built another object called “methods” and inside this is a series of functions. This will be our “internal” methods.

If you look at the buildFaqs() method, the code looks like below:

So you see, we have our SharePoint list data in our array, and we build the HTML from it.

Pagination

Our pagination logic is quite interesting. We use the Bootstrap pagination HTML, and for each page, we need to do a AJAX call in order to get the next page ID. This is how SharePoint determines where to offset the record when a query is made by using “ListItemCollectionPositionNext” as a parameter.

We then proceed to build the actual markup with our internal method: methods.buildPagination():

Each button has an inline “onclick” that calls our public “paginate()” method. Each of them also has the attribute “data-position” which holds the offset “ID” that we talked about:

You noticed too from the code above that we use SPServices on each click. That’s because we are only grabbing a predefined set of records – which is the limit that we pass into our plugin.

Filters

So the plugin supports filtering. This means that you can choose a field from your list and make that a “filter” column.

First, assuming you’ve selected a valid field, we have to build it. Take a look at the code below:

The above simply grabs the data. And since there are duplicate entries – we will have to make them unique and fill up our “_filterByListUnique” array. This is next:

The above builds out the checkboxes we need for our filtering capabilities. Now when each item is clicked, it triggers our filter() method:

Which actually calls our internal methods.filter() method:

A lot going on here. You see that we make a new AJAX call through SPServices, passing our filter value. We parse the response, rebuild our items through “methods.buildFaqs()” and rebuild our pagination through buildPagination().

There’s much more logic in the plugin such as the creating the CAML queries – but I decided not to go through them. If you’re well versed with .NET and SharePoint – you will be able to decipher these easy.

Console Debugging

Once you have the code in place – save and refresh your page. If by any reason some of the options are passed incorrectly, error handling is added and will be displayed in the HTML. You also need to turn on the console for more messages of what’s going on. I’ve added a couple of helpers that will get you information about your list such as getAllColumns(). This will display all of the fields that belong to the list you’re working with. Simply use the instance name + getAllColumns().

Conclusion

As you can see, we can make SharePoint internal lists work responsively. We may have to redo the markup entirely – but there are web services in place to grab the data. Thanks to open source code such as SPServices, jQuery and Bootstrap – our task becomes somewhat easier.

Feel free to comment below.

25 Comments

  1. I’m trying to understand the relationship between this method and using JSLink or if they are unrelated / can be combined. I’ve seen that listed as the optimal way to change the rendering of list views. What are your thoughts?

    Reply
      • Curious as to how the Question/Answer plays out in a different Sharepoint Library – have a document library and trying to use this and I can’t seem to win with the Answer field.

      • Add a custom column and call it “Answer” for now? Also, make sure it’s named “Answer” as the internal name. SP creates an internal name for the columns.

      • Not sure I’m following you still. Sorry couldn’t reply to your response, wouldn’t let me.
        I have a Sharepoint Library, it seems to find the Library of documents. It seems to find library as when I put a random name in the name field it returns and error and when I have the correct name, it doesn’t return an error. In that library I have Name, Topic, Types, etc.. fields. I added an Answer field/column but not I understand how that helps. I tried “answer”: “Answer” or “” (blank) and it returns invalid field name for Answer: Answer. How would I get it to pull all documents within that particular library?

  2. First, this is an excellent solution with many good helpers included. Thank you for sharing! I did have one question that is puzzling me. I have a list with many items but only wanted to display those items that are approved to be displayed. I found the query function works great for the filters because the numbers shown when you ShowCategories is correct. However when buildfaqs function executes it will still display all items even if the approved column = false. I tried to add the viewName option for SPservices but that still is not working as expected. Do you have any ideas? Thanks again.

    Reply
    • I am hunching it’s the column name that you cannot find. SharePoint does funny things to the internal names of the fields. In the plugin, it has a function called “this.getAllColumns()” – simply run that in the console. You have to prepend with the object name ie. spBL233565656.getAllColumns();

      Now in the console, search for that column that is giving you problems, see if the internal name matches your query.

      Reply
  3. This seems to work perfect thanks!
    The only issue I seem to have is when I try to filter by a certain field. I change the FilterBy value in the html file, and reload, I get a message saying ” checking for pages… which just wont load.

    Any idea where I could be going wrong?

    Reply
    • It’s most likely that SP has assigned an internal name that is different than what you are adding in the html file. There is a helper function that you can run -> spBL233565656.getAllColumns() – simply replace the “spBL233565656” with your instance id and you should see a list of columns from that list. Look for your column and use that as the filterby.

      Reply
      • One final question!
        With regards to order, how do you specify which filter by value goes first?
        Right now I think it is done by list length

  4. One final question!
    With regards to order, how do you specify which filter by value goes first?
    Right now I think it is done by list length

    Reply
    • I believe the filter values do not have a sort order. So it actually takes the order of which record goes first. Meaning, which list item has the specific filter value entered, will go first.

      I can add a default sort by alpha in the next version.

      Reply
  5. Interesting, learned a lot from this example – thank you!
    Curious though – in Edge it won’t render at all, however in Chrome or Firefox all is good.
    Also, not sure why my bottom previous/1-2-3/next appear as bullets instead of the clean formatted in your example above.

    Reply
  6. Great job!!
    I was wondering if you have away to render images. For me the “answer”, when using an SP Picture column type, only renders the URL and not the image.
    I tried tricking it using the following:
    record.answer = resp.attr(‘ows_’ + _settings.answer).replace(/^.*(\\|\/|\:)/, ‘&#60 img src &#61 &#34 https://sitename/ifc/TCOP/NWemployees/‘).replace(“,”,’&#34 &#62’);
    Result:

    Reply
    • I believe the picture column type returns a string with two values separated by a delimiter. You can do a .split() and get the value you need.

      Reply

Leave a Comment.