WeedallAboutIT

Musing on life, IT and programming by Chris Weedall

Infinite scrolling with an ASP.net webform, jQuery, and a little bit of code

Infinite scrolling presents your content as one long page – as you read (scroll) toward the bottom of the content some more loads in below automatically (and hopefully seamlessly). This allows your site visitor to focus on content without being distracted by enforced navigation concepts such as paging. It also means you only serve as much content as the user wants to see, which is especially useful in today’s increasingly mobile world. Twitter and Facebook are good examples of sites that do this well.

This post aims to give a hopefully simple example of how to achieve this using the following basic ingredients:

  • ASP.net/C# 4.0 (I’m using Visual Web Developer Express)
  • An ASP.net webform
  • A ScriptMethod
  • jQuery and a bit of JavaScript
  • Some data – in this case a list of pretend blog posts

How it works

The webform will display the first ten blog posts. When the user scrolls to the bottom of the page some JavaScript will call a method to return the next ten items. These are then appended to the bottom of the page. When the user scrolls to the bottom of that the process repeats until there are no blog posts left.

This is simplified for us by the use of a ScriptMethod, which is like a WebMethod in a web service, except you place it in a normal ASPX page as a static method decorated with the ScriptMethod attribute (code example below). ASP.net then kindly provides a nice JavaScript proxy for us to call this with one line of code. I’m then using jQuery to simplify the process of adding the resulting array of BlogPost items to the page.

Blog Post Repository

First things first, we need some data to display and so I have created a static class BlogPostRepository which provides access to a list of made up BlogPost items:

public class BlogPost
{
	public string Title { get; set; }
	public string Summary { get; set; }

	public BlogPost(string title, string summary)
	{
		Title = title;
		Summary = summary;
	}
}

public static class BlogPostRepository
{
	static List<BlogPost> posts;

	static BlogPostRepository()
	{
		posts = new List<BlogPost>();

		for (int i = 1; i <= 200; i++)
		{
			posts.Add(new BlogPost(string.Format("Post number {0}", i),
				string.Format("Discover my thoughts on the number {0}.", i)));
		}
	}

	public static List<BlogPost> GetPosts(int startAt, int howMany)
	{
		return (from p in posts
			select p).Skip(startAt).Take(howMany).ToList();
	}
}

The code behind page

The code behind for the web page is straightforward – bind the first ten posts to a ListView control during Page_Load, and the ScriptMethod GetPosts will return additional blog posts to the page on request:


protected void Page_Load(object sender, EventArgs e)
{
	if (!IsPostBack)
	{
		lvItems.DataSource = BlogPostRepository.GetPosts(0, 10);
		lvItems.DataBind();
	}
}

[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod()]
public static List<BlogPost> GetPosts(int startAt, int howMany)
{
	return BlogPostRepository.GetPosts(startAt, howMany);
}

Note that GetPosts is decorated as a WebMethod and also a ScriptMethod. It also needs to be static.

The mark up

The key to making Script Methods work is the which needs to have EnablePageMethods set to “true”:

<asp:ScriptManager runat="server" ID="ScriptManager1" EnablePageMethods="true">
</asp:ScriptManager>

This ensures that the necessary JavaScript helper methods are available.

Next up is a ListView control which I really like because of the control it offers over the output in your page. This takes care of the initial output of blog posts:


<asp:ListView runat="server" ID="lvItems">
	<LayoutTemplate>
		<div id="container">
			<asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
		</div>
	</LayoutTemplate>
	<ItemTemplate>
		<div class="post">
			<h2>
				<%# Eval("Title") %></h2>
			<p>
				<%# Eval("Summary") %></p>
		</div>
	</ItemTemplate>
	<AlternatingItemTemplate>
		<div class="post shade">
			<h2>
				<h2>
					<%# Eval("Title") %></h2>
				<p>
					<%# Eval("Summary") %></p>
		</div>
	</AlternatingItemTemplate>
</asp:ListView>       

You will notice that each blog post has a container DIV with a class of “post”, and that they are all held within a container DIV with an ID of “container”. Alternate posts have a shaded background thanks to some CSS and the additional “shade” class. The next thing is to add the JavaScript:


<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - $(window).height()) {
            GetPosts();
        }
    });
});

function GetPosts() {
    var howMany = 10;
    var startAt = $(".post").size();
    PageMethods.GetPosts(startAt, howMany, OnGetPostsComplete);
}

function OnGetPostsComplete(posts) {
    for (var i = 0; i < posts.length; i++) {
        var shade = (i % 2) != 0 ? " shade" : "";
        $("#container").last().append("<div class=\"post" + shade + "\"><h2>" +
                            posts[i].Title + "</h2><p>" +
                            posts[i].Summary + "</p></div>");
    }
}
</script>

Lets look at the script above. First I use jQuery to attach a function to the scroll event of the window. This will fire whenever the user scrolls to the bottom of the page, and simply calls the GetPosts method.

GetPosts uses jQuery to get a count of items in the page with the class “post”. This will equal the number of blog posts output so far. I can then call a JavaScript method provided for us by ASP.net because the GetPosts method in our code behind is decorated as a ScriptMethod. So PageMethods.GetPosts takes the same parameters as the C# code, plus in addition the name of the method to call when the asynchronous web call has completed – i.e. when we have the results of the call, in this case OnGetPostsComplete

OnGetPostsComplete takes the array of BlogPost items returned by the ScriptMethod and appends them to the end of the items already in the container DIV which holds all of the blog post DIVs. For effect I’m adding the “shade” class to alternate post items which I have defined in CSS to give them a different background colour.

What next

I haven’t tried this with a database as a data source so speeds will vary. When using the in-memory repository there was hardly a noticable delay at all in the new items being displayed. You might want to add an AJAX style “spinner” graphic to show when loading is occurring. This can easily be achieved using a hidden DIV and the jQuery toggle() method, e.g. $("#loading").toggle();. Toggle it on in GetPosts, and off again in OnGetPostsComplete.

C# JavaScript


Previous post:
Website revamp

Next post:
Creating mazes

© 2009-2024 Chris Weedall