In this article I will explain how to implement Infinite Scroll or Endless Scroll technique in ASP.Net where database records are fetched dynamically on browser page scroll down using jQuery AJAX.
 
Database
For this article I am using Customers Table of Microsoft’s Northwind SQL Server database. You can download the Northwind database using the link below
 
HTML Markup
I have used ASP.Net Repeater control in order to bind the first set of records when the page loads. Once page is loaded and user scrolls the browser jQuery comes into action and it appends the data to this ASP.Net Repeater control.
<table>
<tr><td>
    <div id="dvCustomers">
        <asp:Repeater ID="rptCustomers" runat="server">
            <ItemTemplate>
                <table cellpadding="2" cellspacing="0" border="1" style="width: 200px; height: 100px;
                border: dashed 2px #04AFEF; background-color: #B0E2F5">
                <tr>
                    <td>
                        <b><u><span class="name">
                            <%# Eval("ContactName") %></span></u></b>
                    </td>
                </tr>
                <tr>
                    <td>
                        <b>City: </b><span class="city"><%# Eval("City") %></span><br />
                        <b>Postal Code: </b><span class="postal"><%# Eval("PostalCode") %></span><br />
                        <b>Country: </b><span class="country"><%# Eval("Country")%></span><br />
                        <b>Phone: </b><span class="phone"><%# Eval("Phone")%></span><br />
                        <b>Fax: </b><span class="fax"><%# Eval("Fax")%></span><br />
                    </td>
                </tr>
            </table>
            <br />
            </ItemTemplate>
        </asp:Repeater>
    </div>
</td>
<td valign="bottom">
    <img id="loader" alt="" src="loading.gif" style="display: none" />
</td>
</tr>
</table>
 
 
Implement Pagination in SQL Server Stored Procedure
Since we need to get data on demand i.e. in parts we need to have pagination capability in our stored procedure so that we can fetch records based on page index or page number. This stored procedure returns Total Page Count as OUPUT parameter; this count will help notify jQuery that it should stop making AJAX calls as the all the data has been fetched.
USE [Northwind]
GO
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
 
 
 
Binding first set of records to Repeater
Below code binds the first set of records to the ASP.Net Repeater control in Page Load event. This is very necessary as jQuery needs some HTML content which it can replicate the data fetched via AJAX
C#
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        rptCustomers.DataSource = GetCustomersData(1);
        rptCustomers.DataBind();
    }
}
 
public static DataSet GetCustomersData(int pageIndex)
{
    string query = "[GetCustomersPageWise]";
   SqlCommand cmd = new SqlCommand(query);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@PageIndex", pageIndex);
    cmd.Parameters.AddWithValue("@PageSize", 10);
    cmd.Parameters.Add("@PageCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output;
    return GetData(cmd);
}
 
private static DataSet GetData(SqlCommand cmd)
{
    string strConnString = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
    using (SqlConnection con = new SqlConnection(strConnString))
    {
        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(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    If Not IsPostBack Then
        rptCustomers.DataSource = GetCustomersData(1)
        rptCustomers.DataBind()
    End If
End Sub
 
Public Shared Function GetCustomersData(ByVal pageIndex As Integer) As DataSet
    Dim query As String = "[GetCustomersPageWise]"
    Dim cmd As SqlCommand = New SqlCommand(query)
    cmd.CommandType = CommandType.StoredProcedure
    cmd.Parameters.AddWithValue("@PageIndex", pageIndex)
    cmd.Parameters.AddWithValue("@PageSize", 10)
    cmd.Parameters.Add("@PageCount", SqlDbType.Int, 4).Direction = ParameterDirection.Output
    Return GetData(cmd)
End Function
 
Private Shared Function GetData(ByVal cmd As SqlCommand) As DataSet
    Dim strConnString As String = ConfigurationManager.ConnectionStrings("constr").ConnectionString
    Dim con As SqlConnection = New SqlConnection(strConnString)
    Dim sda As SqlDataAdapter = New SqlDataAdapter
    cmd.Connection = con
    sda.SelectCommand = cmd
    Dim ds As DataSet = New DataSet
    sda.Fill(ds, "Customers")
    Dim dt As DataTable = 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 Function
 
 
WebMethod to handle AJAX calls from jQuery
The following web method handles the jQuery AJAX calls when page is scrolled down. It simply fetches the records from the database and the returns the XML.
C#
[WebMethod]
public static string GetCustomers(int pageIndex)
{
    return GetCustomersData(pageIndex).GetXml();
}
 
VB.Net
<WebMethod()> _
Public Shared Function GetCustomers(ByVal pageIndex As Integer) As String
    Return GetCustomersData(pageIndex).GetXml
End Function
 
 
Client side implementation to make AJAX call on page scroll
In the below code snippet, in the window scroll event of jQuery I am calling the GetRecords JavaScript method which makes an AJAX call to the server and fetches the customer records from SQL Server Database page wise using the current page index.
Every time data is fetched the page index is incremented and when the page index equals the total page count, it disables the process of making jQuery AJAX calls to server.
<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;
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
            GetRecords();
        }
    });
    function GetRecords() {
        pageIndex++;
        if (pageIndex == 2 || pageIndex <= pageCount) {
            $("#loader").show();
            $.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 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");
        customers.each(function () {
            var customer = $(this);
            var table = $("#dvCustomers table").eq(0).clone(true);
            $(".name", table).html(customer.find("ContactName").text());
            $(".city", table).html(customer.find("City").text());
            $(".postal", table).html(customer.find("PostalCode").text());
            $(".country", table).html(customer.find("Country").text());
            $(".phone", table).html(customer.find("Phone").text());
            $(".fax", table).html(customer.find("Fax").text());
            $("#dvCustomers").append(table).append("<br />");
        });
        $("#loader").hide();
    }
</script>
 
 
 
Demo
 
Downloads