Providing Filter Dropdowns for a SharePoint List/Library with jQuery

Let’s say your users want to have an easy way to filter items in a SharePoint list or library, but for some specific reason they should be able to do this with some other functionality than the standard filtering made available in the list&library column header. With a little help of jQuery and SPServices you can easily achieve this and add some dropdowns onto a page, and you can even easily add a nice design (though I’ll leave this part out of this article and leave it up to you to implement with some CSS).

 


What we want to achieve

The following screenshot shows how this solution allows you to apply filters to a list similar to the way these standard column header filters work. As you can see, filters for the columns SingleLineOfText and Number have been applied already, I could also apply another filter for Currency.

Image(1)

You have the choice which columns you want to be filterable here. If you have 5 columns (Name, Address, ZIP, City, Country), you could supply filters for 2 columns (City, Country) only!

The benefit of this solution here is that it works anywhere. For example, you can use it in combination with a Data View Web Part instead of the standard list/library Web Part (Edit: DVWP work differently than the “normal” list/library web parts; I’m currently testing how to integrate this solution with them). Another option would be to provide users with nicer looking filter dropdowns somewhere else on the page (on top of the library; to the right; embedded within some descriptive text!; etc).
Also, this is probably the easiest way to get a dropdown of all possible unique filter values.

 


Background Information

The filters here do not recreate the standard filter menus, but rather reuse SharePoint’s very own creation mechanism (the same way that these standard menus are created). Basically, the filter menu for a list/library is created through JavaScript. You can find the relevant function addFilterMenuItems in the core.js file . Diving into its functionality, once can see that SharePoint actually calls the file /_layouts/filter.aspx when creating the filter menus. If you open this page manually with the relevant parameters, you get to see that it creates a dropdown just the way we need it:

Image(2)

An example for this URL is:
http://myserver/mysubsite/_layouts/filter.aspx?ListId=%7B8A624345%2DDB60%2D41E6%2D9863%2D3DAF60557DA1%7D&FieldInternalName=Region&ViewId={CDBA0419-769D-4AFB-9152-6D311DE99879}&FilterOnly=1&Filter=1

These relevant parameters are:

  1. the ID of the list/library that you’re using (ListId)
  2. the ID of the view that you’re using (ViewId)
  3. the name of the column that we want to filter (FieldInternalName)

Information about how to find all these parameters is listed further below in this article.

It is also important to note the following things:

  1. If one or more filters are applied, all other filters will take them into account. If I filter by Number in my example above, the dropdown for Currency will only show me the values for those rows which meet the Number filtering as well.
  2. If SharePoint doesn’t allow you to filter a field (e.g. multiple lines of text), you can’t filter it here

The important question is: how do we get the values from this dropdown onto our page?

In the discussion board of SPServices you can find a thread that briefly discusses how to retrieve the dropdown itself as well as it’s values. With some modifications, this code can be used for our solution.

 

The Code

The code below consists of two parts, a JavaScript section (including jQuery and SPServices usage) to retrieve the dropdown and prepare its output as well as a simple HTML section where we present the result of the JavaScript code.

//update the following 2 lines with your own local versions if wanted
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.SPServices/2014.01/jquery.SPServices.min.js"></script>
<script type="text/javascript">
$("document").ready(function() {
//set default vars; replace them with your ownvar
listID = '{B858515E-A827-4444-98DA-E81B4F1AF0AD}';
var viewID = '%7B3C11FBF2%2D9702%2D4B76%2DB280%2D02A783B8E7FA%7D';
//load paramsvar
allVars = $().SPServices.SPGetQueryString();
var filterFieldsParams = "";
$.each(allVars, function( objKey, objValue ){
if(objKey.substr(0,11).toLowerCase()=="filterfield" || objKey.substr(0,11).toLowerCase()=="filtervalue"){
filterFieldsParams+="&"+objKey+"="+objValue;
}
});

function getAjaxFilter(name, internalName){
$.ajax({
url: $().SPServices.SPGetCurrentSite()+'/_layouts/filter.aspx?ListId='+listID+'&FieldInternalName='+internalName+'&ViewId='+viewID+'&FilterOnly=1&Filter=1'+filterFieldsParams,
success: function(data) {
// replace"<b>"+name+": </b>" with your own code if required
$('#filterField'+internalName).html("<b>"+name+": </b>").append($("<div></div>").append(data).find("select, img"));
//clear current onChange event
$("#diidFilter"+internalName).attr("onchange", '');
// add change event
$("#diidFilter"+internalName).change(function() {
FilterField(viewID,internalName,encodeURIComponent(this.options[this.selectedIndex].value), this.selectedIndex);
});
}
});
}
// provide selected filters
getAjaxFilter("Single Line of Text", "SingleLineOfText");
getAjaxFilter("Number", "Number");
getAjaxFilter("Currency", "Currency");
});
</script>
<div id="allFilters">
<div id="filterFieldSingleLineOfText"></div>
<div id="filterFieldNumber"></div>
<div id="filterFieldCurrency"></div>
</div>

 


Explanation

The first two lines load the necessary jQuery and SPServices scripts. In the beginning of the JavaScript code block, we first define the ID of the list/library and the view, and then to fetch any filter parameters that may have been applied already from the URL. In such a case, we want our filters to take into account any existing filters, so that unrealistic filter options are not shown (as mentioned under Background Information).

The function getAjaxFilter is the core of this solution. It calls the above mentioned filter.aspx page and fetches its data, filters it to return only any dropdown and any images (if a filter is applied, an icon is shown), and updates the dropdowns onChange event. The reason for this is that the default behaviour in this case doesn’t work properly when you want to remove a filter (when you select (All) from the dropdown). What we need to do here is to simply call the exact same JavaScript function FilterField (defined in core.js) with the correct parameters.

After the function declaration, we have 3 function calls, which you will later need to r
eplace with your own. Lastly, there are three named DIVs which are used later to “store” the results from the getAjaxFilter calls. They follow the naming convention filterFieldINTERNALFIELDNAME, so you need to update them accordingly with your own column names (see below for how to find them out).

 


Using it on your own page

As mentioned above, there are multiple ways how you can include this solution on your page. The easiest way is to add a Content Editor Web Part (CEWP) and paste the code into its Source Editor.

What you’ll need to apply it to your own list/library is the ID of it as well as the ID of the view that you’re using. Both IDs can be in either of the following two formats:
%7BB858515E%2DA827%2D4444%2D98DA%2DE81B4F1AF0AD%7D
or
{B858515E-A827-4444-98DA-E81B4F1AF0AD}

How do you get both required IDs? When you open the settings page of the list/library, you can find its ID as part of the URL:

Image(3)

An easy way to get the ID of the view that you’re using is to apply a filter through the list/library’s header row. Afterwards you can find the ID as part of the URL:

Image(4)

To get the internal name that is used for a column, go to the list/library’s settings, and click on the column name. The internal name can then be found as part of the URL as the parameter Field:

Image(5)

Please note that if you used certain special characters while creating the column, SharePoint will not use them for the internal name, but replace them with hex codes (http://abstractspaces.wordpress.com/2008/05/07/sharepoint-column-names-internal-name-mappings-for-non-alphabet/):

Image(6)

You will still need to bring these columns into a more readable format. For example, if you copy the name marked here (My%5Fx0020%5F1st%5Fx0020%5FTest%5Fx0020%5FColumn%5Fx0021%5F), and decode it at http://meyerweb.com/eric/tools/dencoder/, you will get the actual proper name My_x0020_1st_x0020_Test_x0020_Column_x0021_ which needs to be used

Once you have all these, replace the IDs in the code with your own, and create your own DIV wrappers and getAjaxFilter calls for your respective columns.

 


Possible Improvements

There are still some improvements that could be done. Depending on your own requirements (for example if you wish to reuse that code in multiple locations), you may want to consider calling getAjaxFilter with filterFieldsParams as parameter to avoid relying on it as a global variable. Also, this implementation is not flexible when it comes to creating output in different layouts. If you want to have different ways of displaying the filters (in a table row / with different style sheets / etc), I’d recommend to not do any output changes (namely the $(‘#filterField’+internalName).html(..) call), but rather return the result from getAjaxFilter and use it in your own function for further changes.

Post Media Link

Rene Modery

Having worked with SharePoint since 2007, Rene has been involved in and responsible for two Asia Pacific wide SharePoint implementations.Equipped with a Master’s degree in Information Systems and various relevant certifications, Rene keeps a keen interest in technology and how it can provide solutions to common problems, but also looks at the "business side of IT".He lives in Singapore with his wife and two cats. He has been awarded as a Office 365 MVP by Microsoft in April 2012