SharePoint: Filter a List Dynamically
How do you filter a list based on a parameter entered by the user?
For that we have the default “TextFilter” webpart, but this webpart has two flaws:
First you need the Enterprise version of SharePoint 2010, then this webpart only use the “equal to” and not the “contains” (when all the requests I have personally been asked a “contains”).
I’ll show you a code snippet to add used in a webpart to give your users the ability to filter your lists.
The idea is to load a “ListViewWebPart” of the targeted list.
string listUrl = "Lists/maliste" ;
SPList list = web.GetList(SPUrlUtility.CombineUrl(web.Url, listUrl));
ListViewWebPart lvwp = new ListViewWebPart();
lvwp.ListName = list.ID.ToString("B").ToUpper();
lvwp.ViewGuid = list.Views[YourCustomViewName].ID.ToString("B").ToUpper();
this.Controls.Add(lvwp);
With this code snippet, you will display the list on the url “listUrl” with the view whose name is equal to “YourCustomViewName”
If you want to display the default view, replace the line
lvwp.ViewGuid = list.Views[YourCustomViewName].ID.ToString("B").ToUpper();
by
lvwp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
For the filter, we will use two TextBox, one for the column “LinkTitle” and one for the column “FirstName” and a filter button. The trick will be to create a CAML Query and injecting it in the selected view.
Warning, if the selected view is already filtered, the existing filter will be replaced. In other words if you have a filtered list of column C, if you use the following code snippet, it will not be filtered on column C but on columns A and B.
Let’s start by creating our request.
string query = string.Empty;
string tempAdding = string.Empty;
if (!string.IsNullOrEmpty(tbA.Text))
{
query = <Contains><FieldRef Name='A' /><Value Type='Text'>" + tbA.Text + "</Value></Contains>;
}
if (!string.IsNullOrEmpty(tbB.Text))
{
tempAdding = <Contains><FieldRef Name='B' /><Value Type='Text'>" + tbB.Text + "</Value></Contains>;
query = (query.Length > 0 ? "<And>" + query + tempAdding + "</And>" : tempAdding);
}
Now we will inject the query! For this we will go through the xml view to find the tag “Where” where we will replace the existing query with the new.
XmlDocument doc = new XmlDocument();
doc.LoadXml(lvwp.ListViewXml);
XmlNode queryNode = doc.SelectSingleNode("//Query");
XmlNode whereNode = queryNode.SelectSingleNode("Where");
if (whereNode != null) queryNode.RemoveChild(whereNode);
XmlNode newNode = doc.CreateNode(XmlNodeType.Element, "Where", String.Empty);
newNode.InnerXml = query.ToString();
queryNode.AppendChild(newNode);
lvwp.ListViewXml = doc.OuterXml;
We just have to put it all in one update panel and there you are with a custom filter webpart!
Feel free to go further and put the url of the list, the view and fields in the webpart’s parameters for a filter webpart as generic as possible!
Finally here is the complete code of my webpart.
public class WebPart1 : System.Web.UI.WebControls.WebParts.WebPart
{
TextBox tbA;
TextBox tbB;
Button filterButton;
UpdatePanel mainUpdatePanel;
ListViewWebPart lvwp;
SPList list;
protected override void CreateChildControls()
{
mainUpdatePanel = new UpdatePanel();
mainUpdatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
tbA = new TextBox();
tbB = new TextBox();
list = SPContext.Current.Web.GetList(SPUrlUtility.CombineUrl(SPContext.Current.Web.Url, "Lists/FilterList"));
lvwp = new ListViewWebPart();
lvwp.ListName = list.ID.ToString("B").ToUpper();
lvwp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
lvwp.ChromeType = PartChromeType.None;
filterButton = new Button();
filterButton.Text = "Filter";
filterButton.Click += new EventHandler(filterButton_Click);
Controls.Add(new LiteralControl(" Nom : "));
Controls.Add(tbA);
Controls.Add(new LiteralControl(" Prenom : "));
Controls.Add(tbB);
mainUpdatePanel.ContentTemplateContainer.Controls.Add(filterButton);
mainUpdatePanel.ContentTemplateContainer.Controls.Add(lvwp);
this.Controls.Add(mainUpdatePanel);
}
private void filterButton_Click(object sender, EventArgs e)
{
string query = string.Empty;
string tempAdding = string.Empty;
if (!string.IsNullOrEmpty(tbA.Text))
{
query = "<Contains><FieldRef Name='LinkTitle' /><Value Type='Text'>" + tbA.Text + "</Value></Contains>";
}
if (!string.IsNullOrEmpty(tbB.Text))
{
tempAdding = "<Contains><FieldRef Name='Prenom' /><Value Type='Text'>" + tbB.Text + "</Value></Contains>";
query = (query.Length > 0 ? "<And>" + query + tempAdding + "</And>" : tempAdding);
}
XmlDocument doc = new XmlDocument();
doc.LoadXml(lvwp.ListViewXml);
XmlNode queryNode = doc.SelectSingleNode("//Query");
XmlNode whereNode = queryNode.SelectSingleNode("Where");
if (whereNode != null) queryNode.RemoveChild(whereNode);
XmlNode newNode = doc.CreateNode(XmlNodeType.Element, "Where", String.Empty);
newNode.InnerXml = query.ToString();
queryNode.AppendChild(newNode);
lvwp.ListViewXml = doc.OuterXml;
}
With some modifications you can change this code to apply it for different scenarii as filter on current user, on current current user groups, on url parameter , etc...
For specific sample, you can check the msdn posts where this question was asked :
- http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopmentprevious/thread/f49f1b09-e7ca-4571-b1de-1ae6f9dbf5c8
- http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopment/thread/302b2e22-393c-436e-b334-931d69dabd76
- http://social.technet.microsoft.com/Forums/en-US/sharepointgeneralprevious/thread/5e347dea-475e-4b95-8905-0f6e11bab7bf
- http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopmentprevious/thread/18e53436-35a4-4016-ba7f-2ffd3ec66927
- http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopmentprevious/thread/e804e70c-361c-4be5-a73f-52966eed0948
- http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopmentprevious/thread/2b2840e4-cf5c-41fc-b5c7-659bec04e3b7
- http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopmentprevious/thread/0242a00d-970a-422c-ac37-f1eb4e5cbdea
Initial post : http://christopherclementen.wordpress.com/2012/04/02/filter-a-list-dynamically/
Hope this helps!
Christopher.