When we have large amount of data to display on a page, generally we use paging to display the data to the end user.
The disadvantage of using paging approach is that the user is required to click to the next page. The user is then no longer thinking about what they are reading, but about how to get more to read.
This breaks the user’s train of thought and forces them to stop reading. Pagination creates a natural pause that lets the user reevaluate if he or she wants to keep going on or leave the site, which they a lot of the time do.
It can be argued that Continuous Scrolling can be frustrating for the user, as there is no natural pause. The user will ask himself: When am I done reading?
According to UI-Patterns , following is the usage of Continuous scrolling.
Usage
* Use when there are more data to show than what would fit on a normal page
* Use when navigating to a second page of data takes away too much attention from the content
Solution
In contrast to the Pagination patterns, the Continuous Scrolling pattern has no natural break. When using pagination patterns, a decision to only show a subset of data at a time and then let the user request more data if wanted is chosen. With the Continuous Scrolling, new data is automatically retrieved as the user has scrolled to the bottom of the page. It thus appears as if the page has no end, as more data will be loaded and inserted into the page each time the user scrolls to the bottom of page.
Mixing both pagination and scrolling pattern could be more effective like loading data on page scroll untill a limit is reached and ask the user to click on next button if the user wants to read more.
Like display initially 25 records, then load data as user scrolls down to the page and if total records reached to 100 then display paging to the user to fetch next page of records.
Live example is the updates feed in the account home page at facebook.com , you see more content as you scroll down to the page untill a limit is reached and then older posts link is displayed.
I found it a very nice feature.
So i decided to implement a similar kind of functionality in asp.net. My post is based on M.V. 'Anil' Radhakrishna article. You can find the original post from here. I have corrected few issues with scrolling and added feature to stop scrolling after some limit so that user can request more records by clicking button instead of scrolling infinitely.
Before we start going deep into the details of the implementation, i assume that you know the basics of Jquery because most of the stuff we will do is in Jquery.
So here we go.
First of all create a website in Visual studio.
On the default.aspx, put the following code
<asp:ScriptManager ID="sm1" runat="server">
<Scripts>
<asp:ScriptReference Path="~/Scripts/jquery-1.4.1.js" />
</Scripts>
</asp:ScriptManager>
<h1 style="color: Green">
Scroll to view more content in the grid</h1>
<div id="divProducts" style="height:300px;overflow:auto">
<asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" EnableViewState="false"
GridLines="None">
<AlternatingRowStyle BackColor="White" />
<FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
<HeaderStyle CssClass="header" BackColor="#990000" Font-Bold="True" ForeColor="White" />
<PagerStyle BackColor="#FFCC66" ForeColor="#333333" HorizontalAlign="Center" />
<RowStyle BackColor="#FFFBD6" ForeColor="#333333" />
</asp:GridView>
</div>
<div>
<asp:Button runat="server" Text="Get More records" ID="btnGetMoreRecords"
onclick="btnGetMoreRecords_Click" />
</div>
<div id="divProgress" style="margin-top: -50px;margin-left:150px;z-index:-999">
<img src="loading.gif" width="100" height="100" alt="" />
</div>
<div>
<asp:HiddenField runat="server" ID="hiddenLastProductID" />
</div>
In the above code, we have simply referenced jquery script file in scriptmanager. For the UI, we have put a gridview inside a div which has fixed height of 300px and overflow is set to scroll so that we can scroll the data of the gridview. Gridview will be populated initially with 14 records from the Products table in NorthWnd database in sql server. You can download the sample northwnd database from here.
The button "btnGetMoreRecords" will be displayed to the user only when total no of records being displayed in the gridview reaches a limit.
divProgress is used to show loading effect when user scroll the div and contents are being loaded inside the gridview. I have also used a hidden field to store value of last ProductId that will be used to fetch more records from the database when user clicks on "btnGetMoreRecords" button.
In code behind of the page, we have simply bind the grid and written code for btnGetMoreRecords button.
using System;
using System.Web.UI;
using System.Data;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
NorthwndDB db = new NorthwndDB();
//Fetch 14 records initially.
DataSet dsProducts=db.GetProducts();
//Bind data to gridview
GridView1.DataSource = dsProducts;
GridView1.DataBind();
}
}
protected void btnGetMoreRecords_Click(object sender, EventArgs e)
{
NorthwndDB db = new NorthwndDB();
//Fetch next 14 records after the last product id
DataSet dsProducts = db.FetchNextProducts(Convert.ToInt32(hiddenLastProductID.Value), 14);
//Bind data to gridview
GridView1.DataSource = dsProducts;
GridView1.DataBind();
}
}
You can find the complete code in the end of this post. Till now we have just created UI and written some code for displaying data on the page.
Now let's move towards the jquery logic. In jquery, we will bind the scroll event of the div whose Id is "divProducts" to a function that will first detect if the scrollbar has reached to the end. If the scrollbar has reached to the end of the div, it will make an ajax call to the async handler to fetch more records from the database and append it to the last row of the gridview.
To bind and detect the end of the scroll , we will use the following jquery code.
var previousProductId = 0;
//Max records to display at a time in the grid.
var maxRecordsToDisplay = 30;
$(document).ready(function () {
//initially hide the loading gif
$("#divProgress").hide();
//initially hide the button
$("#btnGetMoreRecords").hide();
//Attach function to the scroll event of the div
$("#divProducts").scroll(function () {
var scrolltop = $('#divProducts').attr('scrollTop');
var scrollheight = $('#divProducts').attr('scrollHeight');
var windowheight = $('#divProducts').attr('clientHeight');
var scrolloffset = 20;
if (scrolltop >= (scrollheight - (windowheight + scrolloffset))) {
//User has scrolled to the end of the grid. Load new data..
$("#divProgress").ajaxStart(function () {
$(this).show();
});
$("#divProgress").ajaxStop(function () {
$(this).hide();
});
BindNewData();
}
});
});
In the above jquery code, we have used three terms, scrollTop, scrollHeigth and clientHeight
scrollTop()
Description: Get the current vertical position of the scroll bar for the first element in the set of matched elements.
scrollHeight
Returns the total height of an element's contents, in pixels. The value contains the height with the padding, but does not include the scrollBar, border, and the margin.
ClientHeight
Returns the height of the visible area for an object, in pixels. The value contains the height with the padding, but it does not include the scrollBar, border, and the margin.
So if the difference between scrollHeight and clientheight is equal to the scrolltop value, we can say that scrollbar has reached to its end. We have optionally taken an offest value of 20 so as load content as soon as scroll bar is going to reach its end.
After that we have initiated a call to handler passing it the value of last product id in the gridview by querystring inside the BindData function.
function BindNewData() {
var lastProductId = $("#GridView1 tr:last").children("td:first").html();
//get last table row in order to append the new products
var lastRow = $("#GridView1 tr:last");
//Fetch records only when the no. of records displayed in the grid are less than limit.
if (GetRowsCount() < maxRecordsToDisplay) {
if (parseInt(lastProductId, 10) > parseInt(previousProductId, 10)) {
previousProductId = lastProductId;
$.post("FetchRecordsHandler.ashx?lastProductId=" + lastProductId, function (data) {
if (data != null) {
//append new products rows to last row in the gridview.
lastRow.after(data);
}
});
}
}
else {
//Set value of last product id in hidden field so that we can access it from code behind.
$("#hiddenLastProductID").val(lastProductId);
//Check If there is more records in the database
if (parseInt(lastProductId, 10) > parseInt(previousProductId, 10))
$("#btnGetMoreRecords").show();
}
}
In the handler, we will use this Id to fetch next set of records and prepare html table rows so that we can directly append them to the gridview using jquery.we will bind the new data using BindData function in javascript.
The code for the handler is as follows:
<%@ WebHandler Language="C#" Class="FetchRecordsHandler" %>
using System;
using System.Web;
using System.Data;
using System.Text;
public class FetchRecordsHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//Delay to create loading effect.
System.Threading.Thread.Sleep(500);
int lastProductId = Convert.ToInt32(context.Request.QueryString["lastProductId"]);
context.Response.Write(GetProductsRows(lastProductId));
}
private string GetProductsRows(int lastProductId)
{
//Fetch records from the DB
NorthwndDB db = new NorthwndDB();
DataTable dtProducts = db.FetchNextProducts(lastProductId,4).Tables[0];
StringBuilder sb = new StringBuilder();
System.Data.DataRow rowProduct;
if (dtProducts.Rows.Count > 0)
{
for (int rowIndex = 0; rowIndex < dtProducts.Rows.Count; rowIndex++)
{
//The below logic is for applying alternate row style
if (rowIndex % 2 != 0)
sb.Append("<tr>");
else
sb.Append("<tr style='color:#333333;background-color:#FFFBD6;'>");
rowProduct = dtProducts.Rows[rowIndex];
for (int j = 0; j < dtProducts.Columns.Count; j++)
{
sb.Append("<td>" + rowProduct[j] + "</td>");
}
sb.Append("</tr>");
}
}
return sb.ToString();
}
public bool IsReusable
{
get
{
return false;
}
}
}
Following is the screen shot of the final run.

To download the complete code, click on the below link.
ContinuousScrollingDemo.zip (196.12 kb)