Filter a list dynamically


Hello everyone,

Today I’ll talk about a request I had more than once lately, whether it’s with my clients or on msdn forums where the issue came up several times : How to filter a list based 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;

        }

Christopher.

8 thoughts on “Filter a list dynamically

  1. Sebastián T.

    Hi Chistopher, very good solution. I’m just looking something similar.

    I tried to run this example (simple, only with title) but is not working to me. I did it on MOSS 2007 whit a default list view. I extract the resultant xml and it’s ok. Any idea to do that or review?

    Greetings, Sebastián.-

      1. Sebastián T.

        Hi Christopher, thanks for your quick reply. Yes, it’s showing me the original view without apply the new filter. Now, I try with another list filter by a lookup value (Neq ‘Final’) and here is the xml…

        CD/DVD

  2. this

    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;

    it is so complicated, you can do the same things by these lines of code

    SPView view = list.Views[YourCustomViewName];
    view.Query = “your query”;
    lvwp.ListViewXml = view.GetViewXml();

    1. Hello Alexander,

      I know that it’s complicated but when a tested the way you describe I had some trouble with the display not updating correctly. I’m thinking about updating this one when I will have some times. Thanks for the suggestion!

  3. Lina Jibreel

    when I wrote ListViewWebPart it gave the below error

    The type or namespace name ‘ListViewWebPart’ could not be found (are you missing a using directive or an assembly reference?)

Leave a comment