When you think ASP, think...
Recent Articles xml
All Articles
ASP.NET Articles
Related Web Technologies
User Tips!
Coding Tips
spgif spgif

Book Reviews
Sample Chapters
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Stump the SQL Guru!
Web Hosts
Author an Article
spgif spgif

ASP ASP.NET ASP FAQs Feedback topnav-right
Print this Page!
Published: Wednesday, January 6, 2010

Using ASP.NET 3.5's ListView and DataPager Controls: Creating an SEO-Friendly Paging Interface

By Scott Mitchell

A Multipart Series on ASP.NET's ListView and DataPager Controls
This article is one in a series of articles on ASP.NET's ListView and DataPager controls, which were introduced with ASP.NET version 3.5.

  • Displaying Data with the ListView - looks at the ListView control basics, with demos on how to display data using the LayoutTemplate and ItemTemplate.
  • Grouping Data with the ListView Control - shows how to render different formatting or encasing markup to every N rendered records.
  • Sorting Data with the ListView Control - shows how to include buttons to sort the ListView's data.
  • Paging Through Data with the ListView and DataPager Controls - shows how to page through the ListView's data using the DataPager control.
  • Grouping By a Data Field - learn how to group the data in a ListView based on the actual data coming from the database.
  • Deleting Data - see how to delete the data bound to the ListView control.
  • Editing Data - learn how to edit the data bound to the ListView control.
  • Inserting Data - explore inserting new records directly from within the ListView control's interface.
  • Creating an SEO-Friendly Paging Interface - learn how to configure the DataPager to render an SEO-friendly paging interface.
  • The Ultimate DataPager Interface - create the ultimate DataPager interface using ASP.NET Routing.
  • Introduction

    The GridView, FormView, and DetailsView controls all contain built-in paging functionality. By setting a few properties, it's possible to have any of these controls automatically include a paging interface. The ListView, however, does not include built-in paging functionality. Instead, Microsoft decoupled the paging logic from the ListView and moved it into a separate Web control - the DataPager. Paging Through Data with the ListView and DataPager Controls, an earlier article in this series, explored how to use the DataPager to implement a paging interface for the ListView.

    By default, the DataPager renders Buttons, LinkButtons, or ImageButtons in the paging interface for the Next, Previous, First, Last, and numeric page number buttons. When clicked, these buttons cause a postback, at which point the appropriate set of records are bound to the ListView. Unfortunately, search engines cannot crawl a site using postbacks; instead, they rely on links they find on your site. Consequently, a search engine will only index the first page of data displayed by a ListView, because it cannot reach the subsequent pages. Also, users cannot bookmark a particular page of data.

    The good news is that it is quite easy to modify the DataPager's default behavior. This article shows how to configure the DataPager to use hyperlinks and the querystring to page through a ListView's data (rather than postbacks) to create an SEO-friendly paging interface. Read on to learn more!

    - continued -

    The Problem With Postbacks

    ASP.NET Web Forms traditionally use postbacks to perform some action. A postback occurs when the user clicks a Button, LinkButton, or ImageButton control, or when they perform some client-side action that has been configured to trigger a postback (such as selecting a different item from a DropDownList control whose AutoPostBack property has been set to True). A postback submits the Web Form, prompting the browser to re-request the same page and to send along the name/value pairs of the <input> elements within the <form>. The ASP.NET page is then re-rendered, with the resulting HTML sent back to the browser for and redisplayed.

    The postback model works well for many scenarios. One of its shortcomings, however, is that it does not result in an SEO-friendly website. SEO, or Search Engine Optimization, is the practice of improving the quality or quantity of traffic that arrives to a site from search engines. An SEO-friendly website is one whose HTML is structured and laid out in such a way that increases the site's visibility to search engine. Search engines use automated programs to index a website. These "crawlers" typically start by visiting the site's homepage and then burrowing into other web pages on the site that are linked from the homepage. Crawlers will follow links, but they won't submit forms. If you have a page where certain content is only visible after a postback then that data will not get indexed by search engines.

    By default, the DataPager renders Buttons, LinkButtons, or ImageButtons for the paging interface. By design, these controls, when clicked, cause a postback. On postback, the DataPager retrieves the requested page of data to display and binds it to the ListView. From the end user's perspective, they click on a page number (or one of the First, Previous, Next, Last buttons) and, voila, the see the appropriate page of data. The problem is that search engine crawlers cannot "click" the buttons in the paging interface and therefore only the first page of results will be indexed. (This SEO-unfriendly behavior is also inherent in the GridView, FormView, and DetailView controls' built-in paging support.)

    Fortunately, the DataPager can generate an SEO-friendly paging interface control. As we'll see momentarily, by setting a single property in the DataPager we can instruct it to render hyperlinks in the paging interface and to use a querystring parameter to indicate what page of data to display.

    Moving the Page Number to the QueryString

    The DataPager includes a QueryStringField property that, if set, instructs the DataPager to generate an SEO-friendly paging interface. If the QueryStringField property is set, the DataPager renders the paging interface as a series of hyperlinks (instead of rendering the paging interface as a series of Buttons, LinkButtons, or ImageButtons). Specifically, each hyperlink has its href attribute set to the current URL with the page number passed included in a querystring field whose name is the value of the QueryStringField property.

    For example, consider a DataPager control that is configured to show First, Previous, Next, and Last buttons, and that there are five total pages of data being paged through. Setting the DataPager's QueryStringField property to "PageNumber" would result in the following paging interface markup when viewing the first page of data:

    <a disabled="disabled">First</a>
    <a disabled="disabled">Previous</a>
    <a href="PageName.aspx?PageNumber=2">Next</a>
    <a href="PageName.aspx?PageNumber=5">Last</a>

    Because we are viewing the first page of data, the First and Previous links are inactive. Inactive links are rendered as hyperlinks with the disabled attribute set. The Next link sends the user to PageName.aspx?PageNumber=2. Here, the PageNumber querystring parameter is set to 2, but more generally it would be set to currentPageNumber + 1. The Last link sends the user to the fifth and final page of data.

    The screen shot below shows the paging interface when rendered as links. The First and Previous links are rendered as text (and not a link) because their disabled attributes are set.

    The ListView's paging interface uses a series of hyperlinks.

    If the user were to click the Next link they browser would request PageName.aspx?PageNumber=2. When the page is rendered, the DataPager automatically checks the querystring for a parameter named the same as its QueryStringField property (in this case, "PageNumber"). Since this querystring field has a value of 2, the DataPager will automatically load the second page of data into the ListView. This time, the paging interface will render the following markup:

    <a href="PageName.aspx?PageNumber=1">First</a>
    <a href="PageName.aspx?PageNumber=1">Previous</a>
    <a href="PageName.aspx?PageNumber=3">Next</a>
    <a href="PageName.aspx?PageNumber=5">Last</a>

    And that's all there is to it! Creating an SEO-friendly DataPager is a simple as setting its QueryStringField property to some value. With this change, search engines can index more than just the first page of data. Additionally, visitors can bookmark a specific page of data, or email the URL to a specific page of data to a friend or colleague.

    Enhancing the Paging User Interface

    The paging user interface shown in the screen shot above leaves a lot to be desired. By setting a few properties and adding a sprinkle of CSS we can improve the paging interface dramatically. For starters, let's enhance the paging interface so that instead of just including First, Previous, Next, and Last links, it also includes numeric page numbers. In Paging Through Data with the ListView and DataPager Controls we saw how to specify the DataPager's paging interface via DataPagerFields. The DataPager in the screen shot above contained a single DataPagerField, namely a NextPreviousPagerField pager field. We can add numeric pages as well by using three DataPagerFields:
    • A NextPreviousPagerField for the First and Previous options,
    • A NumericPagerField for the numeric pages, and
    • A NextPreviousPagerField for the Next and Last options.
    Here's the DataPager's declarative markup once these three DataPagerFields have been added and appropriately configured:

    <asp:DataPager runat="server" QueryStringField="Page" ...>
          <asp:NextPreviousPagerField FirstPageText="&lt;&lt;" ShowFirstPageButton="True" ShowNextPageButton="False" />
          <asp:NumericPagerField />
          <asp:NextPreviousPagerField LastPageText="&gt;&gt;" ShowLastPageButton="True" ShowPreviousPageButton="False" />

    Note that the first NextPreviousPagerField is configured to that the FirstPageText property is set to "&lt;&lt;", which will render the text << for (rather than First). Also, its ShowNextPageButton property is set to False so as to hide the Next button. (The Last button is hidden by default.) Similarly, the second NextPreviousPagerField is configured to suppress the Previous page button and to display the text >> for the Last button.

    The screen shot below shows the new paging interface when viewed through a browser.

    The ListView's paging interface now includes numeric pages in addition to First, Previous, Next, and Last links.

    We can gussy up the appearance with a pinch of CSS. The NextPreviousPagerField and NumericPagerField have properties that allow you to assign a CSS class to the numeric page links, to the current numeric page link, and to the First, Previous, Next, and Last links. After setting these properties, along with setting the RenderNonBreakingSpacesBetweenControls property to False so as to omit a space between each link in the paging interface, and adding the necessary CSS rules, the resulting paging interface has been transformed to the following:

    The ListView's paging interface has been enhanced with CSS.

    Note how the current page number is highlighted. In the above screen shot, the user is viewing page 1, which is why the "1" link has a red background and white foreground, whereas the other links in the paging interface have inverted colors (a red foreground on a white background). Also, when hovering your mouse over a paging link its border and text turns black, subtly highlighting it.

    The download available at the end of this article has the complete CSS rules and property settings needed to implement the above paging interface.

    QueryStringField and RenderDisabledButtonsAsLabels - A Tale of an ASP.NET Bug

    As we explored earlier in this article, when rendering links the DataPager adds the disabled attribute to hyperlinks that are not clickable, such as the First and Previous links when viewing the first page of data. Unfortunately, such markup is not XHTML-compliant, as the strict XHTML implementation disallows the disabled attribute on the <a> element. The NextPreviousPagerField class has a RenderDisabledButtonsAsLabels property, which sounds like the perfect solution. Unfortunately, this doesn't work in ASP.NET version 3.5 - when the DataPager's QueryStringField property is set the RenderDisabledButtonsAsLabels is ignored. The good news is that this bug is fixed in .NET 4.0. (See Using a DataPager with both a QueryStringField and RenderDisabledButtonsAsLabels for a more thorough description on the problem in ASP.NET 3.5, as well as a workaround.)

    In addition to breaking XHTML compliance, this bug also makes it harder to have the disabled buttons styled differently. For instance, the previous screen shot shows the first page of data, meaning that the First and Previous links are inactive, yet those links appear clickable. Granted, if you hover your mouse over them you'll quickly see that they cannot be clicked, but ideally these disabled links would be displayed differently, using a gray text color, perhaps.

    My workaround in this situation was to use a touch of jQuery, which is a JavaScript library designed for enumerating, inspecting, and modifying elements in the HTML DOM. In a nutshell, the page includes a single line of JavaScript code that executes when the page is loaded. This JavaScript code finds all <a> elements with the disabled attribute that use a specific CSS class (pagerButton), removes that class, and then adds an alternate CSS class (pagerButtonDisabled), which displays the inactive links using a gray text color and removing the border. (While not shown above, I have set the NextPreviousPagerField control's ButtonCssClass property to pagerButton, which associates that CSS class with each of the four First, Previous, Next, and Last links.)

    Here is that single line of JavaScript code:


    With this in place, the paging interface now "grays out" the inactive paging links, as illustrated in the following screen shot.

    jQuery is used to gray out inactive paging links.


    By default, the DataPager renders its paging interface using Button, LinkButton, or ImageButton controls. When a visitor clicks one of these paging interface buttons, a postback ensues and the requested page of data is displayed. While this model certainly works, it is does not lead to an SEO-friendly website. With this model, search engines won't index beyond the first page of data. The good news is that the DataPager is designed to render SEO-friendly paging interfaces. By setting the QueryStringField, the DataPager renders its paging interface as a series of links, passing the requested page number through the querystring.

    Happy Programming!

  • By Scott Mitchell

    Further Readings:

  • Paging Through Data with the ListView and DataPager Controls
  • Using a DataPager with both a QueryStringField and RenderDisabledButtonsAsLabels
  • RenderDisabledButtonsAsLabels attribute on the DataPager fields does not work when the QueryStringField attribute on the DataPager is set
  • Attachments

  • Download the Demo (in ZIP format)

  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article