Building a customized document library filtering using content editor webpart and javascript

This is a very long overdue post, I have implemented this back in SPS 2003 and same approach works in current version of SharePoint either WSS or MOSS. In this post I will cover how you can implement a custom document library filtering functionality into your site using content editor webpart, javascript, and xml with out writing any assembly code. 

For demonstration purpose I’ll use the default “documents” document library and added 2 custom columns department and language respectively. Department column is a lookup column based on custom list called “Departments”. Departments custom list contains all departments. The second column language is a choice column with English, Spanish, and French values

I also created a new custom page and added the content editor webpart and the list view webpart for “documents” document library. There are two re-usable javascript libraries used in this solution, I will provide a link to download them at the end of the post, after you download the script files, you can create a document library within your site to store those scripts as we will be referencing those scripts.

Implementing the filter criteria Interface using content editor webpart

HTML snippet below is added to content editor webpart, contains 2 select controls one for departments and the other for author (depending on your requirements this might vary for your scenario). I also have a language field which will display dropdown, radio button or checkbox depending on how the choice column is configured on server, finally there is a button control, when user clicks on it, will implement document library filtering using the criteria specified.

 <table id="filterCriteriaTable">
     <tr>
         <td>Department:</td>
         <td><select id="departmentsDropDownList" /></td>
         <td>Author :</td>
         <td><select id="authorDropDownList" /></td>
     </tr>
     <tr>
         <td>Language:</td>
         <td colspan="3"></td>
     </tr>
     <tr>
         <td colspan="4"><input type=Button Value="Filter" onclick="Filter();"/></td>
     </tr>
 </table>
Preview of Filter Page

filterDocLibPost

Javascript References

There are two javascript references that need to be added right above the HTML snippet shown above in the content editor webpart. I’m referencing script files from “_layouts” directory, like I mentioned earlier you can always create a document library in your site, upload these files and reference the script files from document library directly instead of “_layouts”

    1: <script type="text/javascript" language="javascript" src="/_layouts/SharePointListHelper.js" />
    2: <script type="text/javascript" language="javascript" src="/_layouts/DropDownLoader.js" />

SharePointListHelper.js is a javascript library that provides sharepoint lists webservice integration, makes low level SOAP calls using the “XmlHttp” object. SharePointListHelper supports both synchronous and asynchronous calls to sharepoint list webservice methods. DropDownLoader script library has one public method “LoadDropDown” which is used to databind an HTML select control to a sharepoint list and uses methods in SharePointListHelper library for list integration.

Binding HTML Select in content editor webpart to a sharepoint list

The filter criteria interface implemented with content editor webpart contains 2 dropdown list controls, department and author, If you take a close look at the HTML snippet you’ll notice there are no option elements defined inside the select tag, this is because we want to dynamically bind it to sharepoint list (‘departments’, ‘userinfo’ respectively).

Add the Javascript code snippet from below to the content editor webpart. As you can see in the “LoadDropDowns” helper function I’m constructing a DropDownLoader object which is defined in the “DropDownLoader.js” by passing url as parameter, immediately followed by a call to “LoadDropDown” method. Since we have 2 dropdown controls Department and Author we are calling “LoadDropDown” method twice one for each select control. Again your scenario this might be different. Since we want the “LoadDropDown” method to run when the page is loaded a call to “_spBodyOnLoadFunctionNames.push” accomplishes that.

    1: function LoadDropDowns()
    2: {
    3:     var ddl = new DropDownLoader("https://ramgmossdev");
    4:     ddl.LoadDropDown("Departments", "departmentsDropDownList", "ows_Title", "ows_Title", "");
    5:     ddl.LoadDropDown("UserInfo", "authorDropDownList", "ows_Name", "ows_Name", "");
    6: }
    7: _spBodyOnLoadFunctionNames.push("LoadDropDowns");

Figure below show HTML select control in content editor webpart bound to a sharepoint list.

filterDocLibPost4

Displaying the Language choice column in Filter Criteria View

Goal here is to display the language column based on how its configured in sharepoint, for ex ‘DropDown’, ‘Radio Buttons’, or ‘CheckBoxes’. In the javascript code snippet inserted below from the content editor, I’m getting the document library fields by calling “GetListFields” method on SharePointListHelper which calls ‘GetList’ method on Lists webservice. Once we get the list information from server I look for a Field element with name ‘Language’. If language field is found, code would then dynamically create the element and appends it to the table column.

    1: var languageFieldInfo ;
    2: function AppendInputTag(inputType, inputValue, inputName, tableCell)
    3: {
    4:     var inputElm;
    5:     var spanElm ;
    6:     try
    7:     {
    8:         spanElm = document.createElement("span");
    9:         spanElm.innerText = inputValue ;
   10:        inputElm = document.createElement('<input name="' + inputName + '" type="' + inputType + '" value="' + inputValue + '">' + inputValue + '</input>');
   11:    }
   12:    catch(err)
   13:    {
   14:        inputElm = document.createElement("input");
   15:        inputElm.setAttribute("type", inputType);
   16:        inputElm.setAttribute("value", inputValue);
   17:        inputElm.setAttribute("name", inputName);
   18:    }
   19:    tableCell.appendChild(spanElm);
   20:    tableCell.appendChild(inputElm);
   21: }
   22: function BuildFilterCriteriaView()
   23: {
   24:    var spList = new SPList("https://ramgmossdev");
   25:    languageFieldInfo = spList.GetListFields("Documents").selectSingleNode("Field[@Name = 'Language']");
   26:    if(languageFieldInfo != null)
   27:    {
   28:        var table = document.getElementById("searchTable");
   29:        var fieldType = languageFieldInfo.attributes.getNamedItem("Type");
   30:        var format = languageFieldInfo.attributes.getNamedItem("Format");
   31:        var defaultNode = languageFieldInfo.selectSingleNode("Default");
   32:        var choiceNodes = languageFieldInfo.selectNodes("CHOICES/CHOICE");
   33:        if(fieldType.nodeValue == 'MultiChoice')
   34:        {
   35:           for(var i=0; i<choiceNodes.length; i++)
   36:           {
   37:                AppendInputTag('checkbox', choiceNodes[i].text, 'language', table.rows[1].cells[1])
   38:           }
   39:        }
   40:        else
   41:        {
   42:            switch(format.nodeValue)
   43:            {
   44:                case "Dropdown":
   45:                    var select = document.createElement("select");
   46:                    for(var i=0; i<choiceNodes.length; i++)
   47:                    {
   48:                      var optionElement = document.createElement("OPTION");
   49:                      select.options.add(optionElement);
   50:                      optionElement.innerText = choiceNodes[i].text ;
   51:                      optionElement.value = choiceNodes[i].text;
   52:                      if(choiceNodes[i].text == defaultNode.text)
   53:                      {
   54:                         optionElement.selected = true ;  
   55:                      }
   56:                    }
   57:                    table.rows[1].cells[1].appendChild(select);
   58:                    break;
   59:                case "RadioButtons":
   60:                    for(var i=0; i<choiceNodes.length ; i++)
   61:                    {
   62:                        AppendInputTag('radio', choiceNodes[i].text, 'language', table.rows[1].cells[1])
   63:                    } 
   64:                    break;
   65:            }
   66:       } 
   67:    }
   68: }
   69: _spBodyOnLoadFunctionNames.push("BuildFilterCriteriaView");
Filter It

Since SharePoint document library filtering is all querystring based, we are going to leverage this from a javascript method in content editor webpart. The trick is building the querystring exactly like sharepoint does when you filter a document library.

There is two of things we need find before implementing the filter

  1. view GUID for the “documents” list view.
  2. Internal field names for all columns used in filter criteria view

To find out the view GUID and internal field names you can click on the column header dropdown and select one of the values.

filterDocLibPost2

Copy the GUID and Internal Field Name from the header, also notice the querystring format, we are going to build the querystring similar to it from our filter method so we can leverage out of the box document library filtering

filterDocLibPost3

Filter method in Javascript code snippet below builds querystring based on the filter criteria specified and re-loads the page.

    1: function Filter()
    2: {
    3:     var qs = "?View=%7b7B73B297-4DFA-4E1D-864D-9F00337F4FE6%7d" ;
    4:     var filterField = "FilterField" ;
    5:     var filterValue = "FilterValue" ;
    6:     var i=0;
    7:     var deptDropdown = document.getElementById("departmentsDropDownList");
    8:     var authorDropDown = document.getElementById("authorDropDownList");
    9:     var language = document.getElementsByName("language");
   10:  
   11:    if(deptDropdown != null & deptDropdown.selectedIndex != -1)
   12:    {
   13:        i++;
   14:        qs += "&" + filterField + i + "=Department&" + filterValue + i + "=" + deptDropdown.options[deptDropdown.selectedIndex].value ;
   15:    }
   16:    if(authorDropDown != null & authorDropDown.selectedIndex != -1)
   17:    {
   18:        i++ ;
   19:        qs += "&" + filterField + i + "=Author&" + filterValue + i + "=" + authorDropDown.options[authorDropDown.selectedIndex].value ;
   20:    }
   21:    if(language != null)
   22:    {
   23:        var format = langageFieldInfo.attributes.getNamedItem("Format");
   24:        if(format != null & format.nodeValue == "Dropdown")
   25:        {
   26:            i++;
   27:            qs += "&" + filterField + i + "=Language&" + filterValue + i + "=" + language.options[language.selectedIndex].value ;
   28:        }
   29:        else
   30:        {
   31:            for(var j=0; j<language.length; j++)
   32:            {
   33:                if(language[j].checked)
   34:                {
   35:                   i++;
   36:                   qs += "&" + filterField + i + "=Language&" + filterValue + i + "=" + language[j].value ;
   37:                }
   38:            }
   39:         }
   40:    }
   41:    location.href = GetUrlWithOutQs() + qs ;  
   42: }
   43: function GetUrlWithOutQs()
   44: {
   45:    var url = location.href ;
   46:    var tokens = url.split("?");
   47:    return tokens[0] ;
   48: }

Conclusion

This approach is only a workaround, if out of the box document filtering doesn’t satisfy your requirements and you have constraints on writing assembly code this approach might come handy. You should evaluate all options, custom filter webpart, etc before deciding the correct approach.

You can get the SharePoint Javascript Utilities from MSDN code Gallery