Easy list filtering in SharePoint with jQuery quicksearch

When working with large lists, it’s often a good idea to give the user different ways of navigating the content. SharePoint provides a few good ways out of the box; Metadata Navigation and Filtering, Column Filtering and Sorting and search. One additional way of doing it is using a nifty javascript jQuery plug-in called quicksearch. Thanks to @jankristiansen for showing me this trick.

The easiest way to do this is by simply adding the necessary files (jquery.js and jquery.quicksearch.js) to SharePoint, e.g. the Style Library, and then adding a Content Editor Web Part above the list you want to filter and edit the HTML content of the web part to add an input field and a call to the quicksearch method.

As an example, I’ve added a content editor web part with the following HTML:

<p>
    Filter the list: <input id="filterTxtField" type="text" tabindex="1"/>
</p>

<script type="text/javascript" src="/Style%20Library/Script/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="/Style%20Library/Script/jquery.quicksearch.js"></script>

<script type="text/javascript">
    $(document).ready(function () {
        $('input#filterTxtField').quicksearch('table#onetidDoclibViewTbl0 tbody tr');
    });
</script>

As you can see, I add an inputfield, reference the javascript files and finally hook up the inputfield with the quicksearch when the document has loaded. I’m passing

'table#onetidDoclibViewTbl0 tbody tr'

to the quicksearch-function, which obviously reflects the table rows to filter on. onetidDoclibViewTbl0 is SharePoint’s internal id of the list view, and will vary for different lists or if you have several list views on the page.

The quicksearch-method will search in the whole row, i.e. all the columns. Note that since this is just jQuery, the quicksearch will only search in the items displayed, so you need to display all items. If you want to do search in a similiar way without showing everything on the page, you should check out SPServices.

A better way to utilize this is to create a webpart with this code (could be deployed as a sandboxed solution) to be able to reuse this functionality more easily.

Screenshots of a list with a lot of documents:

all

Screenshot of the library filtering on “Pen”:

pen

Screenshot of the library filtering on “2013”:

2013

No Data Received From Term Stores

Just wanted to quickshare this, as I did not find any solution to this problem using Google. I found this blog that had the same problem, but the proposed solution did not solve the problem for me.

I could not connect to the Managed Metadata Service from my web application / site collection, and when I tried to add new metadata columns I got the error message No Data Received From Term Stores.

NoDataReceivedFromTermStores
No Data Received From Term Stores

When I tried to go throught Site settings –> Term store management tool, I got this error message: “The Managed Metadata Service or Connection is currently not available. The Application Pool or Managed Metadata Web Service may not have been started. Please Contact your Administrator.”

The Managed Metadata Service or Connection is currently not available. The Application Pool or Managed Metadata Web Service may not have been started. Please Contact your Administrator.
The Managed Metadata Service or Connection is currently not available

Turned out the solution was a rather easy one. Under Central Administration –> Service Applications select Configure service application associations (or navigate to /_admin/ApplicationAssociations.aspx). Make sure that the Managed Metadata Service is added as an Application proxy to the web application you are trying to access it from. Pretty obvious really, but not hard to miss.

Service Associations
Service Application Associations

If this doesn’t work, it’s probably a permission issue as discussed here.

Get total number of hits for a query from the results page

I recently had a request from a customer we have implemented FAST Search for SharePoint 2010 for to include a couple of html meta tags on the search result pages. The reason for this is that they use webtrends in addition to SharePoint statistics to log site visits and queries searched for. A webtrends javascript is added to the end of the page. This script sends relevant information to a logging server somewhere else. We wanted to add two new metatags to the page, one for the current query, and one for the total results for this query.

Since the tags should be present on all search result pages, I investigated the page layout for all search result pages, located in \_layouts\masterpages\SearchResults.aspx. In the PlaceHolderPageTitle Contentplaceholder, the title of the page is set by using

<SEARCHWC:SearchTermFromUrl runat="server"/>

where SEARCHWC is registered in the page directive:

<%@ Register Tagprefix="SEARCHWC" Namespace="Microsoft.Office.Server.Search.WebControls" Assembly="Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

Now, displaying this value in a meta-tag is obviously a piece of cake. This can be done in the following way:

<meta name='query' content='<SEARCHWC:SearchTermFromUrl runat="server"/>' />

Getting the number of results for this query was a little harder to do. The first thing I did was investigating the Microsoft.Office.Server.Search.WebControls namespace (The .dll is in the 14-hive/ISAPI folder) by reverse engingeering it with Reflector. I found no similiar method to use to get the number of results.

Lazy as I am, I tweeted the almighty FAST for SharePoint guru Mikael Svenson (check out his blog and twitter), and asked if he had been into something similiar. He suggested to try

<meta name='num_hits' content='<%= SharedQueryManager.GetInstance(this.Page).QueryManager[0].TotalResultsIncludingDuplicates %>' />

where the SharedQueryManager represents the object that executes the query and returns the search results to the SharePoint Enterprise Search results Web Parts. (SharedQuerymanager on MSDN)

I tried this in my page layout, but I got an error which said “Code blocks are not allowed in this file”. I found this blogpost which explains the reason for this error. To fix this, I need to add a line to the PageParserPaths-element in the web.config of my web application. NB: This is generally not best practice!

I added the following line to the PageParserPaths-element:

<PageParserPath VirtualPath="/_catalogs/masterpage/SearchResults.aspx" CompilationMode="Always" AllowServerSideScript="true" />

I previewed the page layout, and eureka, I got a new error: An IndexOutOfBounds exception. Now this is obviously because I’m just previewing the site, not searching for anything (the QueryManager has no queries). I added some basic logic to avoid more errors, and imported the QueryManager in the Page Directive. Oh, and don’t forget that you can only have methods in the script block, because the script is executed at each rquest.

The end result looks like this:

<!-- Default page directives removed for simplicity -->
<%@ Import Namespace="Microsoft.Office.Server.Search.Query" %>
<script type="text/c#" runat="server">
public int getTotalHits() {
	QueryManager mgr = SharedQueryManager.GetInstance(this.Page).QueryManager;
	int numhits = 0;
	if (mgr!= null) {
		if (mgr.Count > 0) {
			numhits = mgr[0].TotalResultsIncludingDuplicates;
		}
	}
	return numhits;
}
</script>

<!-- Default PlaceHolderTitle -->
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
		<asp:literal runat="server" Text="<%$Resources:Microsoft.Office.Server.Search, Search_Results_Page_Title1%>"/> 
		: <SEARCHWC:SearchTermFromUrl runat="server"/>
</asp:Content>

<asp:Content ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
<meta name='num_hits' content='<%= getTotalHits() %>' /><!-- This line is added -->
<meta name='query' content='<SEARCHWC:SearchTermFromUrl runat="server"/>' /><!-- This line is added -->

Now, when I view the source code after a search, I can find in the head-seaction of the html-source:

<meta name='query' content='sharepoint' />
<meta name='num_hits' content='3692' />

This is my blog

So, I’ve finally decided upon investing in a domain and blog hosting.

Countless of times I’ve done something stupid, found a bug, solved a nasty problem, or answered a forum post in depth, I’ve wished I could have kept this information in a central place, for myself to remember. I hope this blog will be such a place. I also hope that the random visitor could pick up something useful here once in a while.

As I’ve called my blog “Developer at War”, I will try to keep a harsh tone when I talk about whatever I fight with that day.