In this article I will explain how to implement Infinite / Endless / Continuous Scroll technique in ASP.Net GridView where database records are fetched dynamically when GridView is scrolled down using jQuery AJAX and Web Methods.
Database
For this article I am making use of the Microsoft’s Northwind database. You can download it using the link below.
HTML Markup
The HTML Markup contains an HTML DIV and an ASP.Net GridView control inside it. I have placed GridView inside the HTML DIV so that we can implement scrolling.
<div id="dvGrid" style="height: 250px; overflow: auto; width: 517px">
<asp:GridView ID="gvCustomers" runat="server" AutoGenerateColumns="false" CssClass="Grid" Width = "500">
<Columns>
<asp:BoundField DataField="ContactName" HeaderText = "Customer Name" ItemStyle-CssClass="name" ItemStyle-Width="200" HeaderStyle-Width="200" />
<asp:BoundField DataField="City" HeaderText = "City" ItemStyle-CssClass="city" ItemStyle-Width="100" HeaderStyle-Width="100" />
<asp:BoundField DataField="Country" HeaderText = "Country" ItemStyle-CssClass="country" ItemStyle-Width="100" HeaderStyle-Width="100" />
<asp:BoundField DataField="PostalCode" HeaderText = "Postal Code" ItemStyle-CssClass="postal" ItemStyle-Width="100" HeaderStyle-Width="100" />
</Columns>
</asp:GridView>
</div>
Now here you need to consider few important things if you need a proper design layout
1. You need specify the ItemStyle-Width and HeaderStyle-Width to each column of the GridView. Make sure both properties have same value for a specific column.
2. The total of all ItemStyle-Width of all columns must be set as Width of the GridView.
3. Finally the width of the HTML DIV must be Width of the GridView plus 17px. 17px is the width of the scrollbar. Example here 500 + 17 = 517px
4. Set the height of the HTML DIV in such a way that by default it should display a scrollbar.
Note: I have set the property ItemStyle-CssClass for each column in GridView; this is done to identify the columns when the data will be populated using jQuery AJAX
CSS Style for the GridView
The following CSS classes are used to provide look and feel for the ASP.Net GridView
<style type="text/css">
.Grid td
{
background-color: #A1DCF2;
color: black;
font-size: 10pt;
font-family: Arial;
line-height: 200%;
cursor: pointer;
width: 100px;
}
.Grid th
{
background-color: #3AC0F2;
color: White;
font-family: Arial;
font-size: 10pt;
line-height: 200%;
width: 100px;
}
</style>
Stored procedure to fetch records on demand when the GridView is scrolled
You will need to execute the following stored procedure in the Northwind Database. The objective of creating the following stored procedure is to get records page wise based on Page Index using the customized paging within the database table using ROW_NUMBER() feature of SQL Server.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetCustomersPageWise]
@PageIndex INT = 1
,@PageSize INT = 10
,@PageCount INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT ROW_NUMBER() OVER
(
ORDER BY [CustomerID] ASC
)AS RowNumber
,[CustomerID]
,[CompanyName]
,[ContactName]
,[City]
,[Country]
,[PostalCode]
,[Phone]
,[Fax]
INTO #Results
FROM [Customers]
DECLARE @RecordCount INT
SELECT @RecordCount = COUNT(*) FROM #Results
SET @PageCount = CEILING(CAST(@RecordCount AS DECIMAL(10, 2)) / CAST(@PageSize AS DECIMAL(10, 2)))
PRINT @PageCount
SELECT * FROM #Results
WHERE RowNumber BETWEEN(@PageIndex -1) * @PageSize + 1 AND(((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1
DROP TABLE #Results
END
Namespaces
You will need to import the following namespaces
C#
using System.Data;
using System.Web.Services;
using System.Configuration;
using System.Data.SqlClient;
VB.Net
Imports System.Data
Imports System.Web.Services
Imports System.Configuration
Imports System.Data.SqlClient
Binding the ASP.Net GridView
Below is the code to bind the GridView using the data fetched from the stored procedure we have created earlier. You will see
C#
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gvCustomers.DataSource = GetCustomersPageWise(1, 10);
gvCustomers.DataBind();
}
}
public static DataSet GetCustomersPageWise(int pageIndex, int pageSize)
{
string constring = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
using (SqlConnection con = new SqlConnection(constring))
{
using (SqlCommand cmd = new SqlCommand("[GetCustomersPageWise]"))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@PageIndex", pageIndex);
cmd.Parameters.AddWithValue("@PageSize", pageSize);
cmd.Parameters.Add("@PageCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output;
using (SqlDataAdapter sda = new SqlDataAdapter())
{
cmd.Connection = con;
sda.SelectCommand = cmd;
using (DataSet ds = new DataSet())
{
sda.Fill(ds, "Customers");
DataTable dt = new DataTable("PageCount");
dt.Columns.Add("PageCount");
dt.Rows.Add();
dt.Rows[0][0] = cmd.Parameters["@PageCount"].Value;
ds.Tables.Add(dt);
return ds;
}
}
}
}
}
VB.Net
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
If Not IsPostBack Then
gvCustomers.DataSource = GetCustomersPageWise(1, 10)
gvCustomers.DataBind()
End If
End Sub
Public Shared Function GetCustomersPageWise(pageIndex As Integer, pageSize As Integer) As DataSet
Dim constring As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
Using con As New SqlConnection(constring)
Using cmd As New SqlCommand("[GetCustomersPageWise]")
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("@PageIndex", pageIndex)
cmd.Parameters.AddWithValue("@PageSize", pageSize)
cmd.Parameters.Add("@PageCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output
Using sda As New SqlDataAdapter()
cmd.Connection = con
sda.SelectCommand = cmd
Using ds As New DataSet()
sda.Fill(ds, "Customers")
Dim dt As New DataTable("PageCount")
dt.Columns.Add("PageCount")
dt.Rows.Add()
dt.Rows(0)(0) = cmd.Parameters("@PageCount").Value
ds.Tables.Add(dt)
Return ds
End Using
End Using
End Using
End Using
End Function
The following screenshot displays the GridView after all the above steps are completed.
Freezing the ASP.Net GridView Header
Now we need to Freeze the GridView Header so that when we scroll the GridView the header row must remain fixed.
Hence for now we need do View Source of the Page and then copy the GridView Header Row HTML as shown below
Then you need to copy the HTML Table of the GridView and the Header Row and paste it just above the HTML DIV that contains the GridView and complete the HTML table ending tag
With the above steps your GridView should now look as following with two headers.
GridView Load Rows on demand when scrolled using jQuery AJAX
Now we will need to create a Web Method which will handle the jQuery AJAX calls when the GridView is scrolled
C#
[WebMethod]
public static string GetCustomers(int pageIndex)
{
//Added to similate delay so that we see the loader working
//Must be removed when moving to production
System.Threading.Thread.Sleep(2000);
return GetCustomersPageWise(pageIndex, 10).GetXml();
}
VB.Net
<WebMethod()> _
Public Shared Function GetCustomers(pageIndex As Integer) As String
'Added to similate delay so that we see the loader working
'Must be removed when moving to production
System.Threading.Thread.Sleep(2000)
Return GetCustomersPageWise(pageIndex, 10).GetXml()
End Function
Now the following JavaScript code needs to be placed on the page, which will complete our task to create an ASP.Net GridView that loads data on demand when scrolled
1. Firstly I have removed the default GridView header row as now it is not required since we need to use the fixed custom header that we have created
2. Then I have attached a jQuery scroll event handler to the HTML DIV, so that we can trigger the process of fetching next set of records when the HTML DIV is scrolled.
3. When a jQuery AJAX request is made to the server Web Method, I am creating a dummy row with a loading GIF image and then appending it as the last row of the GridView, so that we can display some animation until the records are fetched and loaded.
4. When the jQuery AJAX call receives the response as XML string, the XML is parsed and the values are populated using the class names we have given to each GridView column
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
var pageIndex = 1;
var pageCount;
$(function () {
//Remove the original GridView header
$("[id$=gvCustomers] tr").eq(0).remove();
});
//Load GridView Rows when DIV is scrolled
$("#dvGrid").on("scroll", function (e) {
var $o = $(e.currentTarget);
if ($o[0].scrollHeight - $o.scrollTop() <= $o.outerHeight()) {
GetRecords();
}
});
//Function to make AJAX call to the Web Method
function GetRecords() {
pageIndex++;
if (pageIndex == 2 || pageIndex <= pageCount) {
//Show Loader
if ($("[id$=gvCustomers] .loader").length == 0) {
var row = $("[id$=gvCustomers] tr").eq(0).clone(true);
row.addClass("loader");
row.children().remove();
row.append('<td colspan = "999" style = "background-color:white"><img id="loader" alt="" src="103.gif" /></td>');
$("[id$=gvCustomers]").append(row);
}
$.ajax({
type: "POST",
url: "Default.aspx/GetCustomers",
data: '{pageIndex: ' + pageIndex + '}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnSuccess,
failure: function (response) {
alert(response.d);
},
error: function (response) {
alert(response.d);
}
});
}
}
//Function to recieve XML response append rows to GridView
function OnSuccess(response) {
var xmlDoc = $.parseXML(response.d);
var xml = $(xmlDoc);
pageCount = parseInt(xml.find("PageCount").eq(0).find("PageCount").text());
var customers = xml.find("Customers");
$("[id$=gvCustomers] .loader").remove();
customers.each(function () {
var customer = $(this);
var row = $("[id$=gvCustomers] tr").eq(0).clone(true);
$(".name", row).html(customer.find("ContactName").text());
$(".city", row).html(customer.find("City").text());
$(".postal", row).html(customer.find("PostalCode").text());
$(".country", row).html(customer.find("Country").text());
$("[id$=gvCustomers]").append(row);
});
//Hide Loader
$("#loader").hide();
}
</script>
Demo
Downloads