Alphabetical Paging on a SharePoint List View
One of the requirements I have had to work on lately is reproducing elements of a Domino UI in sharepoint. That happens to include a long list of sites with links at the top providing the ability to view sites starting with a particular letter.
This of course is quite different from the standard SharePoint paging/filtering/grouping, which is based on page numbers and full text values.
The first approach I tried was to add a filter provider web part implementing ITransformableFilterValues as documented by Ton Stegeman - MOSS 2007 Filter webparts part 1 – create your own provider and consumer .
Unfortunately, the out of box list view web part doesn’t provide particularly good support for filter providers. Sending the connection from the filter provider fails with the error “AvailableLinks did not implement the GetInitEventArgs method”. Setting up the connection the other way works, but is still quite limited. You can’t filter on a url field, the filter operator is always equals, and you can only filter on a column that is visible in the current view.
The first two constraints mean that we will need to create an additional column “FirstLetter” that is calculated based on the url title.
The third constraint means that we will need to use query string filters instead of a connected web part. Query string filters do have a few limitations, in particular that they apply to every list on the page. However, this will not be a problem in this case as the page will only contain one list view.
The filter portion is easy enough. In the web part render method, create a series of links in the format
<a href="?FilterField1=FirstLetter&FilterValue1=A">A</a>
AlphabetFilterWebPart.cs Render Method
protected override void Render(HtmlTextWriter writer) { try { writer.Write(string.Format("{1} ", "0", "All")); writer.Write(string.Format("{1} ", "0", "0-9")); foreach (char c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()) { writer.Write(string.Format("{1} ", c, c)); } } catch (Exception ex) { writer.Write(ex.Message + " " + ex.StackTrace); } }
Populating the FirstLetter column is a little more complex. A calculated field would be ideal, but that won’t work for a links list as the URL is a complex field type and not supported in a calculated field formula.
The easiest way to handle this is with an event handler. When the link is added or updated, use .net code to update the FirstLetter field.
All the bits not shown are the defaults created by the WSPBuilder templates.
Elements.xml
<?xml version="1.0" encoding="utf-8" ?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Module Name="WebPartPopulation" Url="_catalogs/wp" RootWebOnly="TRUE"> <File Url="AlphabetFilterWebPart.webpart" Type="GhostableInLibrary"> <Property Name="Group" Value="MyGroup"></Property> <Property Name="QuickAddGroups" Value="MyGroup" /> </File> </Module> <Receivers ListTemplateId="103"> <Receiver> <Name>AddFirstLetter</Name> <Type>ItemAdded</Type> <SequenceNumber>10000</SequenceNumber> <Assembly>AlphabetFilter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f633ef6b7fa5501</Assembly> <Class>AlphabetFilter.FirstLetterEventHandler</Class> <Data></Data> <Filter></Filter> </Receiver> <Receiver> <Name>UpdateFirstLetter</Name> <Type>ItemUpdated</Type> <SequenceNumber>10000</SequenceNumber> <Assembly>AlphabetFilter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1f633ef6b7fa5501</Assembly> <Class>AlphabetFilter.FirstLetterEventHandler</Class> <Data></Data> <Filter></Filter> </Receiver> </Receivers> </Elements>
FirstLetterEventHandler.cs
using System; using System.Collections.Generic; using System.Text; using Microsoft.SharePoint; using System.Text.RegularExpressions; namespace AlphabetFilter { public class FirstLetterEventHandler:SPItemEventReceiver { private void SetFirstLetter(SPListItem item) { if (!item.Fields.ContainsField("URL")) return; if (!item.Fields.ContainsField("FirstLetter")) return; SPFieldUrlValue urlvalue = new SPFieldUrlValue(""+item["URL"]); string firstlettervalue = "" + item["FirstLetter"]; string linktitle = urlvalue.Description; if ( !string.IsNullOrEmpty(linktitle) && ( // no first letter string.IsNullOrEmpty(firstlettervalue) // first letter does not match and is not 0 || (firstlettervalue != "0" && !linktitle.StartsWith(firstlettervalue, StringComparison.InvariantCultureIgnoreCase)) // firstlettervalue == 0 iff title starts with number and first letter is not 0 || ((firstlettervalue == "0") == (Regex.IsMatch(linktitle, "^([a-z]|[A-Z]).*")))) ) { // to simplify the filter web part, the value set will always be // an uppercase letter or 0 for other characters. if (Regex.IsMatch(linktitle, "^([a-z]|[A-Z]).*")) { item["FirstLetter"] = ("" + linktitle[0]).ToUpper(); } else { item["FirstLetter"] = "0"; } item.Update(); } } public override void ItemAdded(SPItemEventProperties properties) { base.ItemAdded(properties); SetFirstLetter(properties.ListItem); } public override void ItemUpdated(SPItemEventProperties properties) { base.ItemUpdated(properties); SetFirstLetter(properties.ListItem); } } }
Once this is working, you will want to remove the FirstLetter field from the form. To do this:
1. Enable content type management on the links list
2. Edit the link content type
3. Edit FirstLetter and set it to hidden so it will not appear on forms.
Another option I looked at was using Ishai’s Advanced Content Query web part, as that is already in use on the site and does handle filters properly. However, that would mean replacing the good parts of the out of box list view as well as the bad parts, making it less desirable than the query string filter solution.
If you need to add the paging functionality to another sort of list, filtering on the title column, create FirstLetter as a calculated column with the formula
=IF(ISNUMBER(VALUE(LEFT(Title,1))), “0″, LEFT(Title,1))
Hi Tom,
This is exactly what I’m looking for to deploy on a site that I’m working on. However, I would like to ask, about the above steps.. should they all take place in Sharepoint Designer? I’ll look through my files to make sense of the .cs and .xml files and where they need to go. Any tips, starter points will be helpful
Uzma
May 14, 2008 at 2:26 pm
This is all done in Visual Studio using WSPBuilder. You can do code in SharePoint Designer, but I don’t recommend it.
Tom Clarkson
June 2, 2008 at 8:52 pm
Hi tom,
I have installed the visual studio 2005 and Sharepoin designer.. but i do not know how to get the WSPBuilder?
Any tips what stuff i need to do or get to use that ….
Regards,
Cristina
cristina
October 7, 2008 at 7:26 pm
Try the link on the left of this page.
Tom Clarkson
October 7, 2008 at 7:58 pm
Hello,
thanks for ur very useful article.
will you please explain what is next after implementation?? how we have to deploy it to sharepoint t obe able to see it on the platform ??
Many Thanks
Sally4000
October 30, 2008 at 9:07 am
Deployment method will depend on your environment, but if you package it with WSPBuilder deployment is usually just a matter of running the installer.
Tom Clarkson
October 30, 2008 at 5:06 pm
Hello,
which filter provider web part you have choose??
(Business Data Catalog Filter
Choice Filter
Current User Filter
SharePoint List Filter)
Sally4000
November 12, 2008 at 6:24 am
This is a custom web part, not one of the out of box filter web parts. It doesn’t even use the filter provider / web part connections system – it just renders some links with appropriate stuff in the query string.
Tom Clarkson
November 12, 2008 at 4:43 pm
How can i use the query string method to filter a moss list using a custom field type (eg: URL+Description+Title+Target) but based on just the value of URL ? Do i need to create a calculated column that is filled on ItemCreated with the value of the URL and then filter by that Field ?
joao
December 6, 2008 at 6:14 pm
Hi, Tom
Thank you, it’s very usefull.
Yuk
December 30, 2008 at 8:40 am
Hallo Tom,
Can you tell me where did you put the Elements.xml?
Yuk
January 1, 2009 at 3:26 am
Elements.xml goes in the feature folder – edit the elements.xml created by WSPBuilder.
Tom Clarkson
January 28, 2009 at 12:47 am
Url based filtering is fairly limited – equals only, no other operators. So yes, you may need to create a calculated column that provides the simple field to filter by.
Tom Clarkson
January 28, 2009 at 12:49 am
Hello Tom,
does this solution work for WSS3.0
Samir
April 21, 2009 at 1:23 am
Hi ,
I my system Wspuilder is not there. I have created webpart for alphabets and, classlirary for eventhandler, futures and elements xml files.
It is showng error like
`
__abENT__quot;failed to instantiate file __abENT__quot;__abENT__lt;wepartName__abENT__gt;__abENT__#46;wepart__abENT__quot; from module __abENT__quot;wepartpopulation__abENT__quot; : source path __abENT__quot;__abENT__lt;wepartName__abENT__gt;__abENT__#46;webpart__abENT__quot; notfound__abENT__#46;`And, I have no idea about “wepartpopulation” modules’ job.
So, please let me know the solution.
gem
April 28, 2009 at 2:23 am
Can you briefly expali me aout this
- I am new to sharepoint..
pra
May 1, 2009 at 4:52 am
“Elements of type ‘Receivers’ are not supported at the ‘Site’ scope. This feature could not be installed.”
I am getting this error while deploying (deployement failed). What could be the reason?
anonymous
May 3, 2009 at 12:46 am
very usefull. thanks alot
nima
February 14, 2010 at 6:22 am