To read the article online, visit http://www.4GuysFromRolla.com/articles/101409-1.aspx

Creating a Filtering User Interface With jQuery In a Web Forms Application: Part 2

By Scott Mitchell


Introduction


Creating a Filtering User Interface With jQuery In a Web Forms Application: Part 1 looked at how to use jQuery in an ASP.NET Web Forms application to build a collapsible filtering user interface. When the page is loaded into the user's browser the filtering interface is collapsed. Clicking the filtering interface's title toggles the interface between its collapsed and expanded states. When expanded, a user can interact with the filtering controls - DropDownLists, TextBoxes, CheckBoxes, and so on - to narrow down the results displayed in the report beneath the filtering interface.

While the filtering interface created in Part 1 certainly works, the collapsed/expanded state of the interface is not remembered. Consequently, on any postback or anytime a user leaves the page and comes back, the filtering interface returns to its collapsed state, regardless of whether the user had it expanded. The good news is that with a touch of AJAX we can have the collapsed/expanded state of the filtering user interface remembered for the duration of a user's session. This article explores how to add such functionality. Read on to learn more!

If you've not yet read Part 1, please do so before tackling Part 2.

Programmatically Injecting JavaScript


The JavaScript code used in the demo in Part 1 was entered directly into the markup portion of the ASP.NET page (Demo.aspx):

<script type="text/javascript">
   $(document).ready(function() {
      $('#filterUI').hide();

      $('#filterUItitle').click(function() {
         $('#filterUI').slideToggle(400);
         $('#filterUItitle').toggleClass('expandIcon');
         $('#filterUItitle').toggleClass('collapseIcon');
      });
   });
</script>

This script executes every time the web page is loaded in the browser, whether it's the user's initial visit to the page or if it's a postback. The first line of code in the document ready event handler ($('#filterUI').hide()) hides the filtering user interface, which is why the interface is collapsed when the page loads and after postbacks.

To have the filtering user interface's collapsed/expanded state remembers across page loads we need to do two things:

  1. Have some mechanism that tracks the collapsed/expanded state on a user-by-user basis, and
  2. Be able to show or hide the filtering user interface when the page is loaded based on (1).
We'll talk about ways to implement (1) in a bit, but for now let's focus on (2). In order to show or hide the filtering interface we need to be able to programmatically inject the appropriate JavaScript. If the filtering interface is to be collapsed then we want to inject $('#filterUI').hide(); if it is to be expanded, then we want to inject $('#filterUI').show().

ASP.NET includes a ClientScriptManager class that facilitates programmatically injecting JavaScript code into the page. This class, which is accessible via the Page.ClientScript object, has methods like RegisterClientScriptBlock and RegisterStartupScript, both of which inject script into the rendered page. We can use these methods to inject the document ready event handler with the appropriate script. (This article does not explore the intricacies of adding client-side script to an ASP.NET page from server-side code. For more on that topic refer to Xun Ding's article, JavaScript With ASP.NET 2.0 Pages.)

The demo project available for download at the end of this article includes a custom base page class named BasePage. Creating and using a custom base page class is a helpful means to extend common functionality to all of your ASP.NET pages. For more information on using base page classes and their benefits, see Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes.

The BasePage class in this demo includes a property named jQUeryDocumentReadyStatements, which is a List of strings. BasePage also defines an override for the OnPreRender method, which is the point in the page life cycle when client-side scripts should be added to the ASP.NET page. This overridden method checks to see if there are any strings in the jQUeryDocumentReadyStatements List and, if so, injects a script block with a document ready event handler that contains the specified statements. The following code shows this OnPreRender override:

Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
   'Add jQuery document ready function, if needed
   If jQueryDocumentReadyStatements.Count > 0 Then
      Dim jQueryScript As String = "$(document).ready(function() {"

      For Each stmt As String In jQueryDocumentReadyStatements
         jQueryScript &= String.Concat(vbCrLf, stmt, vbCrLf)
      Next

      jQueryScript &= "});"

      ClientScript.RegisterClientScriptBlock(Me.GetType, "jquery_DocumentReadyCode", jQueryScript, True)
   End If

   MyBase.OnPreRender(e)
End Sub

To programmatically create a document ready event handler from server-side code you will need to do the following:

  1. Have the ASP.NET page derive from BasePage (rather than System.Web.UI.Page).
  2. Add each JavaScript statement to include in the document ready event handler to the jQUeryDocumentReadyStatements collection, like so:

    MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').hide();")

    Or:

    MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').show();")

Doing so will inject JavaScript into the rendered page with a document ready event handler that contains the specified JavaScript statements.

Determining Whether To Collapse Or Expand The Filtering User Interface


The download available at the end of this article includes two demo pages. Demo.aspx is the "dumb" filtering interface, the one that's collapsed whenever the page is loaded (including on postback). DemoSmart.aspx showcases the filtering interface that remembers is collapsed/expanded state for the duration of the user's session. The ShowHideFilterUI method in the DemoSmart.aspx code-behind class is called from the Page_Load event handler on every page visit and injects the appropriate JavaScript. As you can see in the code below, it determines whether to show the filtering user interface in its collapsed or expanded state by consulting a session variable named ShowFilterUI. If that session variable is not set or if it is set to False, then the method injects script that hides the filtering user interface and sets its CSS class to expandIcon, which shows the expand icon in the filter title. However, if this session variable is set to True then script is emitted to show the filtering user interface and to set the CSS class to collapseIcon, which shows the collapse icon.

Private Sub ShowHideFilterUI()
   If Session("ShowFilterUI") Is Nothing OrElse Session("ShowFilterUI") = False Then
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').hide();")
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUItitle').addClass('expandIcon');")
   Else
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').show();")
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUItitle').addClass('collapseIcon');")
   End If

   Dim toggleScript As String = _
      "$('#filterUItitle').click(function() { " & vbCrLf & _
         "   $('#filterUI').slideToggle(400);" & vbCrLf & _
         "   $('#filterUItitle').toggleClass('expandIcon');" & vbCrLf & _
         "   $('#filterUItitle').toggleClass('collapseIcon');"
         "   ... More jQuery code coming here soon! ...

      "});"

   MyBase.jQueryDocumentReadyStatements.Add(toggleScript)
End Sub

Note: The filterUItitle <div> in Demo.aspx has its class attribute explicitly set to expandIcon, as it's always collapsed by default: <div id="filterUItitle" class="expandIcon">...</div>. However, in DemoSmart.aspx this same <div> element does not have its class attribute set explicitly; rather, its set via JavaScript injected from the ShowHideFilterUI method.

In addition to the JavaScript that shows or hides the filtering interface, the ShowHideFilterUI method also adds the script for the filterUItitle <div>'s client-side click event. This code above is identical to that used in Part 1. There's another line of JavaScript we will add to the click event handler in a moment.

Toggling The Session Variable When Collapsing And Expanding The Filtering User Interface


The ShowHideFilterUI shows the filtering user interface as either collapsed or expanded depending on the value of the ShowFilterUI session variable. (If this session variable is not set then the filtering interface is collapsed.) In order to remember the collapsed/expanded state, we need to toggle this session variable when the user expands or collapses the filtering interface. In order to toggle this session variable we need the browser to make a call back to the server whenever the filtering user interface is collapsed or expanded.

With jQuery we can initiate an asynchronous client-side HTTP request with one line of JavaScript. But before we look at that script, let's first create the ASP.NET "page" that will be responsible for toggling the session variable. We need an ASP.NET "page" that, when called, toggles the value of the ShowFilterUI session variable. I use the word page in quotes here because while a page would certainly work, a simpler approach is to use an HTTP Handler. I've implemented a generic HTTP Handler named ToggleFilterState.ashx in the Services folder.

An HTTP Handler's work is handled in its ProcessRequest method. The code for this method is quite simple - if the ShowFilterUI session variable is not yet set or is set to False then the ShowFilterUI session variable is set to True, otherwise it's set to False. The code for this method follows:

Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
   'Toggle the Session variable ShowFilterUI
   If context.Session("ShowFilterUI") Is Nothing OrElse context.Session("ShowFilterUI") = False Then
      context.Session("ShowFilterUI") = True
   Else
      context.Session("ShowFilterUI") = False
   End If
End Sub

The final piece of the puzzle is to have the browser send an HTTP request to ToggleFilterState.ashx whenever the user expands or collapses the filtering user interface. This is accomplished by adding a single line of JavaScript to the client-side click event handler. Returning to the ShowHideFilterUI method that we examined earlier, we need to add a JavaScript statement that uses jQuery's $.get(url) function.

Private Sub ShowHideFilterUI()
   If Session("ShowFilterUI") Is Nothing OrElse Session("ShowFilterUI") = False Then
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').hide();")
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUItitle').addClass('expandIcon');")
   Else
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUI').show();")
      MyBase.jQueryDocumentReadyStatements.Add("$('#filterUItitle').addClass('collapseIcon');")
   End If

   Dim toggleScript As String = _
      "$('#filterUItitle').click(function() { " & vbCrLf & _
         "   $('#filterUI').slideToggle(400);" & vbCrLf & _
         "   $('#filterUItitle').toggleClass('expandIcon');" & vbCrLf & _
         "   $('#filterUItitle').toggleClass('collapseIcon');" & vbCrLf & _
         vbCrLf & _
         String.Format("$.get('{0}');", Page.ResolveUrl("~/Services/ToggleFilterState.ashx")) & vbCrLf & _
      "});"

   MyBase.jQueryDocumentReadyStatements.Add(toggleScript)
End Sub

With the above JavaScript, anytime the filtering user interface is expanded or collapsed, an HTTP request is fired off to the ToggleFilterState.ashx HTTP Handler, which toggles the ShowFilterUI session variable.

With this code in place, let's take a look at a typical sequence of events that might unfold for a user visiting the report page.

  1. The fires up their browser and surfs on over to the report page. Because they are just arriving at the site, there is no ShowFilterUI session variable. Consequently, the filtering user interface is rendered in its default configuration (collapsed).
  2. The user expands the filtering user interface, which sends of an HTTP request to ToggleFilterState.ashx. The ToggleFilterState.ashx HTTP Handler creates the ShowFilterUI session variable, setting it to True.
  3. The user enters some filtering criteria into the filtering controls and clicks the Filter button, causing a postback.
  4. On postback, the page notes that the ShowFilterUI session variable is True and expands the filtering user interface. The user sees both the expanded filtering interface along with the filtered results.
  5. The user leaves the report page and visits a number of other pages on the site.
  6. A few minutes later he returns to the filtering page. The the page notes that the ShowFilterUI session variable is True and therefore expands the filtering user interface.
  7. The user collapses the filtering interface, which sends an HTTP request to ToggleFilterState.ashx. The ToggleFilterState.ashx HTTP Handler sets the ShowFilterUI session variable to False.
  8. The user leaves the report page and visits a number of other pages on the site.
  9. A few minutes later he returns to the filtering page. The the page notes that the ShowFilterUI session variable is False and therefore collapses the filtering user interface.
With the code we had written in Part 1, the filtering interface would have returned to its default, collapsed state in steps (4) and (6). But with our changes, the filtering interface will maintain its last collapsed or expanded state for the duration of the user's session.

Conclusion


jQuery is a free, open source, lightweight, and powerful JavaScript library that greatly simplifies interacting with the DOM, performing animations and other effects, and implementing client-side AJAX functionality. In Part 1 we saw how to use jQuery in an ASP.NET Web Forms application to create a collapsible filtering user interface. In this article we saw how to extend this functionality to have the filtering interface's collapsed/expanded state remembered across the duration of the user's session using a session variable and a pinch of AJAX.

Happy Programming!

  • By Scott Mitchell


    Attachments:

  • Download the code for this article
  • Further Reading


  • JavaScript With ASP.NET 2.0 Pages
  • Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes
  • HTTP Handlers and HTTP Modules in ASP.NET
  • Article Information
    Article Title: ASP.NET.Creating a Filtering User Interface With jQuery In a Web Forms Application: Part 2
    Article Author: Scott Mitchell
    Published Date: October 14, 2009
    Article URL: http://www.4GuysFromRolla.com/articles/101409-1.aspx


    Copyright 2017 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers