Click here to Skip to main content
15,881,852 members
Articles / Web Development / ASP.NET
Tip/Trick

ASP.NET MVC Ajax Infinite Scroll

Rate me:
Please Sign up or sign in to vote.
5.00/5 (23 votes)
3 Nov 2013CPOL2 min read 109.8K   4.4K   27   27
This is a simple infinite scroll with Ajax post and JSON. Have fun :)

Introduction

Infinite Scroll is a web design technique that prevents the browser scroll bar from scrolling to the bottom of the page, causing the page to grow with additional content instead.

Here, I have implemented Infinite Scroll with ASP.NET MVC, Ajax post and JSON result. With rendering Partial View to string, it makes it easy to use Ajax post and JSON result to display any complex view.

Using the Code

You can also find the code on Codeplex.

Getting Data

In this sample for data, we use some XML file with book items.

Here is some part of the XML file:

XML
<book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications with XML.</description>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, an evil sorceress, 
      and he own childhood to become queen of the world.</description>
   </book>   

We use Linq to XML to load data to our Book class, which is:

C#
public class Book
{
    public string ID { get; set; }
    public string Author { get; set; }
    public string Title { get; set; }
    public string Genre { get; set; }
    public string Price { get; set; }
    public string PublishDate { get; set; }
    public string Description { get; set; }
}

For example, at first the user can see 5 books on the page, and when she/he scrolls down, the next 5 books will load and so on.

Number 5 is BlockSize, and BlockNumber is 1 at first, and growing by 1 every time, we scroll down and next block loads. So GetBooks function gives the BlockNumber 'th block with BlockSize books in it.

C#
public static class DataManager
{
    /// <summary>
    /// Returns one block of book items
    /// </summary>
    /// <param name="BlockNumber">Starting from 1</param>
    /// <param name="BlockSize">Items count in a block</param>
    /// <returns></returns>
    public static List<Book> GetBooks(int BlockNumber, int BlockSize)
    {
        int startIndex = (BlockNumber - 1) * BlockSize;

        var filePath = AppDomain.CurrentDomain.BaseDirectory + "testData.xml";
        var doc = XDocument.Load(filePath);

        var books = (from p in doc.Descendants("book")
                    select new Book
                    {
                        ID = p.Attributes("id").Single().Value,
                        Author = p.Element("author").Value,
                        Title = p.Element("title").Value,
                        Genre = p.Element("genre").Value,
                        Price = p.Element("price").Value,
                        PublishDate = p.Element("publish_date").Value,
                        Description = p.Element("description").Value,
                    }).Skip(startIndex).Take(BlockSize).ToList();

        return books;
    }
}

This part is very similar to paging task.

Controllers and Views

To show one block of books, we have an Action with PartialView BookList:

C#
[ChildActionOnly]
public ActionResult BookList(List<Book> Model)
{
    return PartialView(Model);
}
C#
@model List<mvcajaxinfinitescroll.Models.Book>
@foreach (var item in Model)
{
    <div style="height: 300px; background-color: #F3F3F3; margin-bottom: 30px;">
        <div style="padding: 30px; 
        font-size: 25px; color: #7b4f9d">@item.Title</div>
        <div style="padding-left: 30px; 
        font-size: 18px;">Author: @item.Author</div>
        <div style="padding-left: 30px; 
        font-size: 18px;">Genre: @item.Genre</div>
        <div style="padding-left: 30px; 
        font-size: 18px;">Price: @item.Price $</div>
        <div style="padding-left: 30px; 
        font-size: 18px;">Publish Date: @item.PublishDate</div>
        <div style="padding-left: 30px; padding-right: 30px; font-size: 18px;">
        Description: @item.Description</div>
    </div>
}   

On Index Action, we just get the first Block:

C#
public ActionResult Index()
{
    int BlockSize = 5;
    var books = DataManager.GetBooks(1, BlockSize);
    return View(books);
}

and show it on view:

ASP.NET
<div id="bookListDiv">
    @{Html.RenderAction("BookList", "Home", new { Model = Model });}
</div>  

We have InfinateScroll Post Action. It runs every time we scroll page down and need to populate the next block of data.

C#
[HttpPost]
public ActionResult InfinateScroll(int BlockNumber)
{
    //////////////// THis line of code only for demo. Needs to be removed ////
    System.Threading.Thread.Sleep(3000);
    //////////////////////////////////////////////////////////////////////////
    int BlockSize = 5;
    var books = DataManager.GetBooks(BlockNumber, BlockSize);
    JsonModel jsonModel = new JsonModel();
    jsonModel.NoMoreData = books.Count < BlockSize;
    jsonModel.HTMLString = RenderPartialViewToString("BookList", books);
    return Json(jsonModel);
}

This Action returns a Json. We wrote JsonModel class to return here as JsonResult:

C#
public class JsonModel
    {
        public string HTMLString { get; set; }
        public bool NoMoreData { get; set; }
    } 

NoMoreData indicates that this is the last set of data and BlockNumber is the last number.

HTMLString is the HtmlString of BookList view. In this way, it is easy to return JSON and show next block using a little jquery. To get HtmlString, we have function RenderPartialViewToString.

C#
protected string RenderPartialViewToString(string viewName, object model)
        {
            if (string.IsNullOrEmpty(viewName))
                viewName = ControllerContext.RouteData.GetRequiredString("action");

            ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = 
                ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                ViewContext viewContext = new ViewContext
                (ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }

And now let's see JavaScript we use to do Ajax post. On Index view, we have:

JavaScript
 <script type="text/javascript">
    var BlockNumber = 2;  //Infinate Scroll starts from second block
    var NoMoreData = false;
    var inProgress = false;

    $(window).scroll(function () {
        if ($(window).scrollTop() == $(document).height() - 
        $(window).height() && !NoMoreData && !inProgress) {

            inProgress = true;
            $("#loadingDiv").show();
            
            $.post("@Url.Action("InfinateScroll", 
            "Home")", { "BlockNumber": BlockNumber },
                    function (data) {
                        
                        BlockNumber = BlockNumber + 1;
                        NoMoreData = data.NoMoreData;
                        $("#bookListDiv").append(data.HTMLString);
                        $("#loadingDiv").hide();
                        inProgress = false;
                    });
        }
    });
</script> 
C#
<div id="loadingDiv" 
style="text-align: center; display: none; margin-bottom: 20px;">
    <img alt="Loading" 
    src="@Url.Content("~/Content/Images/ajax-loader.gif")" />
</div>  

Please, let me know if you liked it :) ...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Seven Smarts
Armenia Armenia
.Net developer

Comments and Discussions

 
QuestionIts not working in chrome browser Pin
sureshshm26-Nov-17 20:08
sureshshm26-Nov-17 20:08 
GeneralMy vote of 5 Pin
pandiya krishnan16-Nov-17 20:29
pandiya krishnan16-Nov-17 20:29 
GeneralMy vote of 5 Pin
reindeerbreeder5-Oct-17 4:09
reindeerbreeder5-Oct-17 4:09 
GeneralMy vote of 5 Pin
Richard Mneyan1-Mar-17 6:23
Richard Mneyan1-Mar-17 6:23 
QuestionGetting Duplicate records or no recoreds Pin
appumvc12-Jun-15 1:51
appumvc12-Jun-15 1:51 
AnswerRe: Getting Duplicate records or no recoreds Pin
Hovhannes Bantikyan15-Jun-15 6:57
Hovhannes Bantikyan15-Jun-15 6:57 
GeneralRe: Getting Duplicate records or no recoreds Pin
appumvc12-Aug-15 22:50
appumvc12-Aug-15 22:50 
GeneralMy vote of 5 Pin
Member 1071345411-Jun-15 12:25
Member 1071345411-Jun-15 12:25 
BugNot working when zoomed in Pin
Duy H. Thai21-Feb-15 22:05
Duy H. Thai21-Feb-15 22:05 
GeneralRe: Not working when zoomed in Pin
Hovhannes Bantikyan4-Mar-15 13:41
Hovhannes Bantikyan4-Mar-15 13:41 
QuestionRe: Not working when zoomed in Pin
Duy H. Thai5-Mar-15 0:36
Duy H. Thai5-Mar-15 0:36 
AnswerRe: Not working when zoomed in Pin
Hovhannes Bantikyan6-Mar-15 4:52
Hovhannes Bantikyan6-Mar-15 4:52 
GeneralCongrats Pin
Hans Kyburz24-Jan-15 7:07
Hans Kyburz24-Jan-15 7:07 
QuestionLayout page... Pin
Rakesh kumar18-Jan-15 22:52
Rakesh kumar18-Jan-15 22:52 
Questionreading from database istead Pin
Member 1116328930-Oct-14 22:53
Member 1116328930-Oct-14 22:53 
AnswerRe: reading from database istead Pin
Hovhannes Bantikyan8-Nov-14 7:24
Hovhannes Bantikyan8-Nov-14 7:24 
QuestionGREAT!! Pin
hayk.nersisyan22-Jul-14 4:28
hayk.nersisyan22-Jul-14 4:28 
QuestionHow to work with Automatic Image Montage with jquery. Pin
CuongPuyol22-Jun-14 17:00
CuongPuyol22-Jun-14 17:00 
GeneralAwesome thank you! Pin
wendellmva5-Jun-14 14:09
wendellmva5-Jun-14 14:09 
QuestionThank You Pin
Plamen 태권도 Yovchev20-Dec-13 20:58
Plamen 태권도 Yovchev20-Dec-13 20:58 
QuestionCSS after update Pin
Member 1047353117-Dec-13 19:19
Member 1047353117-Dec-13 19:19 
AnswerRe: CSS after update Pin
Member 1047353117-Dec-13 20:56
Member 1047353117-Dec-13 20:56 
Questionneed help... Pin
Kumar Kovuru3-Dec-13 2:57
Kumar Kovuru3-Dec-13 2:57 
AnswerRe: need help... Pin
Hovhannes Bantikyan6-Dec-13 8:58
Hovhannes Bantikyan6-Dec-13 8:58 
GeneralRe: need help... Pin
Kumar Kovuru6-Dec-13 18:57
Kumar Kovuru6-Dec-13 18:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.