5. Alphabetical List View Quick Filter

Update: August 15th, 2010

This article the first of The Power of Content Editor WebPart series. Other parts:

 

This is an easy kind-of hack where we’ll use SharePoint’s URL. Our goal is to have a small section above the list view that will filter the list according to first letter of every item in the list as seen on the screenshot below.

End result

This comes in handy with large lists. In our example we’ll continue to work on the list of customers that we’ve already "pimped" with the quick search functionality.

Let’s take a look at filters

For this purpose we’ll take a look at our list – what happens when we use the list filter:

Applying the filter   Check the URL parameters of an applied filter

The page URL gets additional parameters: View, FilterField1 and FilterValue. For working in list view you can easily skip the View parameter and the filter will still work.

Filter without "View" URL parameter

So FilterField1 determines according to which column the list should be filtered (we have to use column internal names) and FilterValue1 parameter sets the filter value. And yes, since they both have number 1 added to them, you can add multiple filters (FilterField2, FilterValue2, FilterField3, …).

 

Let’s do it

Great. So now we can take advantage of this. Because we don’t want to have each unique value in the filter options we need an additional column with the first name of a customer. The column must be displayed in the view in order for filter to work. For the column to be as discrete as possible, I recommend using a short column name, something like FL (first letter). Let’s go ahead and add the column.

Add a new column

The column should be of type "Calculated" and the formula is simple:

=LEFT([LastName])

The value in square brackets is the display name of the column. When entering the formula the square brackets should also be present. All the settings for a new column are presented below:

Column settings 

And as mentioned the column should be in the view where we’ll add the filter.

The new column added

Time for CEWP and JavaScript

OK. Now let’s insert the CEWP and JavaScript. After insertion, and linking to the external content file the "Hello world" is ready:

CEWP added   Content file with Hello world test

We could do this entirely without the JavaScript. All we’d need is to enter hyperlinks like below:


<a href="AllItems.aspx?FilterField1=FL&FilterValue1=A">A</a> 

<a href="AllItems.aspx?FilterField1=FL&FilterValue1=B">B</a>  <a href="AllItems.aspx?FilterField1=FL&FilterValue1=C">C</a>

And that would just work fine.

Filter with pure HTML Pure HTML solution

But going on the wild side and to raise the complexity of this article I want to make this a bit more dynamic and page-independant. In the code above the problem is that this is bound to the AllItems.aspx page. What if you’d want to re-use the code somewhere else? Plus you have to do a lot of copy-paste and corrections for minor items.

So JavaScript to the rescue. To avoid repetitive typing we’ll create a JavaScript array of all possible values for filter and build the links in a for loop. So first let’s define an array of possible filter values.

<script type="text/javascript">
	var filterValues = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
</script>

Next we create a loop for all of the values to create the filter just before the </script> tag:

for (var i = 0; i < filterValues.length; i++) {
	document.write("<a href="" + document.location.pathname + "?FilterField1=FL&FilterValue1=" + filterValues[i] + "">" + filterValues[i] + "</a>&nbsp;");
}

And that would do the trick. We’d end up with a filter:

image

By using the document.location.pathname in the script we’ve removed strict binding to any particular page.

That’s it. If you’re satisfied with a filter like that you can stop reading right here. If you wish to "pimp" the filter a bit more, continue reading.

Expanding our example

Now let’s add a bit more configurability. We wish to be able to configure a delimiter between the filter values and we wish to be able to configure the filter column. So immediately after the first line (<script type….) add the following two lines:

	var filterField = "FL";
	var filterValuesDelimiter = " : ";

And we’ll modify the for loop to be writing links into a new array instead of directly to the document.  So we modify the loop to take into account the filter field and take out the &nbsp; delimiter at the end. At the end we’ll use a join function for an array of links to add the delimiter between and write to the document.

So we replace entire "for" loop in the code with the following:

	for (var i = 0; i < filterValues.length; i++) {
		filterLinks.push("<a href="" + document.location.pathname + "?FilterField1=" + filterField + "&FilterValue1=" + filterValues[i] + "">" + filterValues[i] + "</a>");
	}
	document.write(filterLinks.join(filterValuesDelimiter));

By now the result should look something like the following:

Script so far.

Alphabet filter

And the first three lines of code give you configuration capabilities for filter field, filter values and filter values delimiter.

Neat. Want to complicate even more? Wouldn’t it be nice if the filter would highlight the selected value? And let’s make the highlighted style also configurable. At the beginning of the script first we need to declare a configuration variable for selected value.

	var selectedValueStyle = "font-weight: bold;";

Now we need to know which filter value is selected. How do we get to know that? In URL we need to read the value of the "FilterValue1" parameter. Since JavaScript has no built-in function for this we need a supporting queryString function. I’ve published one on my JavaScripts Library. It’s the qs function. We’ll insert this function before any JavaScript code, so immediately after the first line. But because we already use the iterator i in the for loop we need to fix the i iterator in the qs function.

	function qs(paramName) {
		var args = document.location.search.substring(1).split("&");
		for(j = 0; j < args.length; j++) {
			nameValues = args[j].split("=");
			if(nameValues[0] == paramName) return nameValues[1];
		}
		return null;
	}

And now we update the for loop in our script to be checking if the value of the FilterValue1 parameter equals the filter value from the array. We do this by injecting the shorthand if statement like the one below:

(qs("FilterValue1") == filterValues[i] ? "style="" + selectedValueStyle + "" " : "")

in the part where the links are being constructed (<a href="…"). The final for loop looks like this:

	for (var i = 0; i < filterValues.length; i++) {
		filterLinks.push("<a " + (qs("FilterValue1") == filterValues[i] ? "style="" + selectedValueStyle + "" " : "") + "href="" + document.location.pathname + "?FilterField1=" + filterField + "&FilterValue1=" + filterValues[i] + "">" + filterValues[i] + "</a>");
	}

And as a final touch let’s not have those links jammed to the upper left corner. We’ll wrap a layer around with a configurable style. So at the beginning of our script we add another parameter:


	var filterDivStyle = "margin: 5px;";

and we update the "document.write" line to add the surrounding div.

document.write("<div style="" + filterDivStyle + "">" + filterLinks.join(filterValuesDelimiter) + "</div>");

And the final result looks like this (having applied filter for "A":

Final result with applied filter "A"

The full code is below:

<script type="text/javascript">
	function qs(paramName) {
		var args = document.location.search.substring(1).split("&");
		for(j = 0; j < args.length; j++) {
			nameValues = args[j].split("=");
			if(nameValues[0] == paramName) return nameValues[1];
		}
		return null;
	}

	var filterField = "FL";
	var filterValuesDelimiter = " : ";
	var filterValues = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
	var selectedValueStyle = "font-weight: bold;";
	var filterDivStyle = "margin: 5px;";
	var filterLinks = new Array();
	for (var i = 0; i < filterValues.length; i++) {
		filterLinks.push("<a " + (qs("FilterValue1") == filterValues[i] ? "style="" + selectedValueStyle + "" " : "") + "href="" + document.location.pathname + "?FilterField1=" + filterField + "&FilterValue1=" + filterValues[i] + "">" + filterValues[i] + "</a>");
	}
	document.write("<div style="" + filterDivStyle + "">" + filterLinks.join(filterValuesDelimiter) + "</div>");
</script>

And because results can be configurable, you can easily vary the look of the alphabet filter. For example a configuration like:

	var filterField = "FL";
	var filterValuesDelimiter = "-";
	var selectedValueStyle = "border: 1px black solid";
	var filterDivStyle = "margin: 5px; font-size: 15px;";

would result in

Variation in filter style

Happy scripting everyone!

Other articles from this series:

  1. Brian
    December 29th, 2010 at 18:53
    Reply | Quote | #1

    This is great. I’ve been looking for something exactly like this and it will work for my needs.

    One question I have would be is there a way to add another link in the “abcd…” array that would clear the filter out? I have messed around with it a little bit, but now knowing what I am doing does not help. Thanks.

  2. Marshall
    February 24th, 2011 at 20:57
    Reply | Quote | #2

    Probably something simple, but is there a way to add an “All” option that would clear the filter?

    • Boris Gomiunik
      May 25th, 2011 at 06:43
      Reply | Quote | #3

      Yep. Just add the hyperlink to the same page you’re viewing without the “FilterField1″ and “FilterValue1″ parameters.

  3. umar
    May 24th, 2011 at 23:32
    Reply | Quote | #4

    Awsome i will try this . but you think it will work with sharepoint 2010 also .
    either way i think its million dollar blog if works

  4. May 27th, 2011 at 21:36
    Reply | Quote | #5

    When I add this to a SharePoint 2010 site, nothing is displayed. I don’t get an opportunity to select any of the A to Z filter values. Somehow the document.write function is not working.

  5. lollita
    June 3rd, 2011 at 15:48
    Reply | Quote | #6

    I cannot seem to get this to work. I am working on SharePoint 2010, everything is setup as above.I have copied the code above onto my CEWP HTML Source….Is there anything else I need to do to get this to work?

  6. Ben
    June 10th, 2011 at 18:32
    Reply | Quote | #7

    Is there a reason why this wouldn’t work with WSS 3.0? When I try it in WSS 3.0 nothing happens.

    • admin
      June 23rd, 2011 at 09:55
      Reply | Quote | #8

      The sample is made also in SharePoint 3. It should be working. Maybe you can debug if the script starts by putting an alert() at the beginning of your script.

  7. umar
    July 1st, 2011 at 14:38
    Reply | Quote | #9

    Les :When I add this to a SharePoint 2010 site, nothing is displayed. I don’t get an opportunity to select any of the A to Z filter values. Somehow the document.write function is not working.

  8. umar
    July 1st, 2011 at 14:40

    lollita :I cannot seem to get this to work. I am working on SharePoint 2010, everything is setup as above.I have copied the code above onto my CEWP HTML Source….Is there anything else I need to do to get this to work?

    Tested . it works with Sharepoint2010 . document.write is working . What it does every time i edit the page and save it back it create another row of filters. that can be some thing with the code but it works fine on sp2010.

TOP