Implement Lazy Loading In MVC

Introduction 

 
This article explains how to implement lazy data  loading on a scroll down page. Lazy loading is a technique to load data on demand which will help to improve page performance. In this article I will demonstrate how to implement lazy loading on page scroll. Once a user uses scroll on the page then on demand data will load from the database using Ajax call.
 
Lazy loading is very useful when you have lakhs of records to load. You can do pagination and load your data based on demand.
 
Here I will explain step by step from scrach, an application to implement lazy loading using ajax call. I have attached the source code for this demo.
 
Step 1
 
Create a new project using the below intrsuctions. First select a new project from Visual Studio and then select Asp.Net Web application as in the below screen,
 
 
 
Step 2
 
Select MVC option from the next screen and click on ok button which will create a new project for you.  
 
 
 
Step 3
 
Right click on the solution and click on Manage NuGet package manager.
 
 
Step 4
 
Search entity framwork package and add reference for entity framwork. Here I have added reference for entity framework v6.4.
 
 
 
Step 5
 
Click on install button and the  I Accept button to install entity framework. 
 
 
 
 
 
 
 Step 6
 
Once entity framework reference is added from nuGet package, add new entity data model to get data from database.
 
 
 
Step 7
 
Once entity data model is added then click on any of below options as per your project requirement. Here I have selected Code first from database approch to create model. 
 
 
 
Step 8
 
Click on next button and create new connection using the below screen, click on new connection button. 
 
 
 
Step 9
 
Select your sql server name and database as shown in the below screen and test connection. 
 
 
 
 Step 10
 
Once connection is succeeded then you are able to see the below screen with connection string.
 
 
Step 11
 
Once connection string is created you will get all tables from your database in the next screen as below. Select the appropriate table from the below screen, here I have selected product table, and click on finish button.
 
 
 
Step 12
 
Add new controller as per your requirement -  here I have added with name ProductController. 
 
 
 
Step 13
 
Once controller is created, click on controller method and add view for your action method. 
 
 
Step 14
 
Select view as partial view, template as list and use Product model beacuse here I am going to use partial view to render our lazy loading data which will come from ajax call response.   
 
 
 
Step 15
 
So far,  we are done with controller, model and view creation. Now we will start code implementation for ajax call and scrollbar event for loading data dynamically once user scrolls down the page. Then based on scroll data it should be loading as per page size set up. In this example I have set page size to 20 so on scroll Ajax call will return 20 records each time.
 
Let's start with creating SQL table and create 10000 records in a table. SQL script to create table and create random records:
 
SQL Script
  1. -- ==================== Create Table ============================  
  2. CREATE TABLE [dbo].[Products](  
  3.     [ProductID] [int] IDENTITY(1,1) NOT NULL,  
  4.     [ProductName] [nvarchar](maxNULL,  
  5.     [Price] [intNOT NULL,  
  6.     [ProductDescription] [nvarchar](maxNULL,  
  7.  CONSTRAINT [PK_dbo.Products] PRIMARY KEY CLUSTERED   
  8. (  
  9.     [ProductID] ASC  
  10. )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ONON [PRIMARY]  
  11. ON [PRIMARY]  
  12. GO  
  13.   
  14. -- ===============================================  
  15. declare @productId int   
  16. select @productId = 1  
  17. declare @ProductName varchar(100)  
  18. declare @Price int  
  19. declare @Productdescription varchar(500)  
  20.   
  21. -- ================================================  
  22. --Loop through 1000 records and insert into table  
  23. -- ================================================  
  24.   
  25. while @productId >=1 and @productId <= 10000  
  26. begin  
  27. set @ProductName = 'PENT - 'CAST(@productId as nvarchar(10))   
  28.     set @Price = 1000  
  29.     set @Productdescription = 'PENT - Description - 'CAST(@productId as nvarchar(10))   
  30.   
  31. if (@productId%2 = 0)  
  32. begin  
  33.     set @ProductName = 'PENT - 'CAST(@productId as nvarchar(10))   
  34.     set @Price = 2000  
  35.     set @Productdescription = 'PENT - Description - 'CAST(@productId as nvarchar(10))   
  36. end  
  37. if(@productId%3 = 0)  
  38. begin  
  39.     set @ProductName = 'Color T-SHIRT - 'CAST(@productId as nvarchar(10))   
  40.     set @Price = 3000  
  41.     set @Productdescription = 'Color T-SHIRT - Description - 'CAST(@productId as nvarchar(10))   
  42. end  
  43. if(@productId%5=0)  
  44. begin  
  45.     set @ProductName = 'Designed Shirt - 'CAST(@productId as nvarchar(10))   
  46.     set @Price = 5000  
  47.     set @Productdescription = 'Designed Shirt - Description - 'CAST(@productId as nvarchar(10))  
  48. end  
  49.     insert into products(ProductName, Price,ProductDescription)   
  50.                 values( @ProductName ,@Price, @Productdescription)  
  51.     select @productId = @productId + 1  
  52. end  
  53. ---====================================================  
 Model
  1. public partial class Product  
  2. {  
  3.     public int ProductID { getset; }  
  4.   
  5.     public string ProductName { getset; }  
  6.   
  7.     public int Price { getset; }  
  8.   
  9.     public string ProductDescription { getset; }  
  10. }  
Repository
  1. public class ProductRepository  
  2.     {  
  3.         private const int pageSize = 20;  
  4.         public List<Product> GetProducts(int? pageNumber)  
  5.         {  
  6.             var numberOfRecordToskip = pageNumber * pageSize;  
  7.             using (var context = new Products())  
  8.             {  
  9.                 return context.ProductsDetails.OrderBy(x=>x.ProductID).Skip(Convert.ToInt32(numberOfRecordToskip)).Take(pageSize).ToList<Product>();  
  10.             }  
  11.         }  
  12.     }  
Controller
  1. namespace LazyLoadingDemo.Controllers  
  2. {  
  3.     public class ProductController : Controller  
  4.     {  
  5.         private ProductRepository productRepository;  
  6.         // GET: Product  
  7.         public ActionResult Index()  
  8.         {  
  9.             return View();  
  10.         }  
  11.         [HttpGet]  
  12.         public ActionResult ProductList(int? pageNumber)  
  13.         {  
  14.             productRepository = new ProductRepository();  
  15.             var model = productRepository.GetProducts(pageNumber);  
  16.             return PartialView("~/Views/Product/ProductList.cshtml", model);  
  17.         }  
  18.     }  
  19. }  
View
  1. @model IEnumerable<LazyLoadingDemo.Product>  
  2.   
  3. <div class="jumbotron">  
  4.     <h2>Lazy Loading Example Using Ajax in MVC Application</h2>  
  5.     <p class="lead">  
  6.         <br />  
  7.         <h4>This is home page where we will try to load partial view.</h4>  
  8.         <span class="text-primary">  
  9.             Once user scroll down page then scroll event gets fire and append records to existing table.  
  10.             It loads only 20 records at a time based on each scroll down event  
  11.         </span>.  
  12.     </p>  
  13. </div>  
  14.   
  15. <div class="table-responsive col-md-12" id="divajaxCall">  
  16.     <div class="jumbotronajaxdiv">  
  17.         <h3>Records get append to this table once user scroll down page.</h3>  
  18.     </div>  
  19.     <table class="table table-striped table-bordered">  
  20.         <thead>  
  21.             <tr>  
  22.                 <th>  
  23.                     @Html.DisplayNameFor(model => model.ProductName)  
  24.                 </th>  
  25.                 <th>  
  26.                     @Html.DisplayNameFor(model => model.Price)  
  27.                 </th>  
  28.                 <th>  
  29.                     @Html.DisplayNameFor(model => model.ProductDescription)  
  30.                 </th>  
  31.   
  32.             </tr>  
  33.         </thead>  
  34.         <tbody>  
  35.             @if (Model != null)  
  36.             {  
  37.                 @Html.Partial("~/Views/Product/ProductList", Model)  
  38.             }  
  39.         </tbody>  
  40.     </table>  
  41.     <div class="row">  
  42.         <div id="loading" style="text-align:center; padding:0 0 0 0">  
  43.             <img src='~/Content/progress-loader1.gif' />  
  44.         </div>  
  45.     </div>  
  46.     <div class="divfooter">  
  47.     </div>  
  48. </div>  
  49. <div id="divHide"></div>  
  50. @section scripts{  
  51.     <script src="~/Scripts/lazyLoading.js"></script>  
  52.     <script type="text/javascript">  
  53.         $(function () {  
  54.             $("div#loading").hide();  
  55.         });  
  56.         var ajaxCallUrl = '@Url.RouteUrl("ProductDataList")';   
  57.   
  58.         $(window).scroll(scrollHandler);  
  59.     </script>  
  60. }  
  61.   
  62. <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">  
  63. <link rel="stylesheet" href="~/Content/CustomStyle.css">  
  64. <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>  
  65. <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>  
Index.cshtml   
  • Partial View
ProductList.cshtml
 
This is partial view which will loop through number of records which comes from ajax call and will return HTML response and append to table where we are going to bind all records base on scroll down page.
  1. @model IEnumerable<LazyLoadingDemo.Product>  
  2. @foreach (var item in Model)  
  3. {  
  4.     <tr>  
  5.         <td>  
  6.             @Html.DisplayFor(modelItem => item.ProductName)  
  7.         </td>  
  8.         <td>@Html.DisplayFor(modelItem => item.Price)</td>  
  9.         <td> @Html.DisplayFor(modelItem => item.ProductDescription)</td>  
  10.     </tr>  
  11. }  
Web.Config
 
Connection string section,
  1. <connectionStrings>  
  2.     <add name="Products" connectionString="data source=XYZ-PC\SQLEXPRESS;initial catalog=ProductDatabase;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />    </connectionStrings>  
Routeconfig
  1. public class RouteConfig  
  2.     {  
  3.         public static void RegisterRoutes(RouteCollection routes)  
  4.         {  
  5.             routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  6.   
  7.             routes.MapRoute("ProductDataList"""new { controller = "Product", action = "ProductList" });  
  8.   
  9.             routes.MapRoute(  
  10.                 name: "Default",  
  11.                 url: "{controller}/{action}/{id}",  
  12.                 defaults: new { controller = "Product", action = "Index", id = UrlParameter.Optional }  
  13.             );  
  14.         }  
  15.     }  
JavaScript for Ajax call
 
lazyLoading.js
  1. var ajaxCallUrl = 'Product/ProductList',  
  2.     page = 0,  
  3.     inCallback = false,  
  4.     isReachedScrollEnd = false;  
  5.   
  6.   
  7. var scrollHandler = function () {  
  8.     if (isReachedScrollEnd == false &&  
  9.         ($(window).scrollTop() + $(window).height() == $(document).height())) {  
  10.         loadProducts(ajaxCallUrl);  
  11.     }  
  12. }  
  13. function loadProducts(ajaxCallUrl) {  
  14.     if (page > -1 && !inCallback) {  
  15.         inCallback = true;  
  16.         page++;  
  17.         $("div#loading").show();  
  18.         $.ajax({  
  19.             type: 'GET',  
  20.             url: ajaxCallUrl,  
  21.             data: "pageNumber=" + page,  
  22.             success: function (data, textstatus) {  
  23.                 if (data != '') {  
  24.                     $("table > tbody").append(data);  
  25.                 }  
  26.                 else {  
  27.                     page = -1;  
  28.                 }  
  29.   
  30.                 inCallback = false;  
  31.                 $("div#loading").hide();  
  32.             },  
  33.             error: function (XMLHttpRequest, textStatus, errorThrown) {  
  34.                 alert(errorThrown);  
  35.             }  
  36.         });  
  37.     }  
  38. }  
Step 15
 
Put URL in browser http://localhost:XXXXX/Product/Index and run application using F5, user should be able to see table with 20 records as in the below screen and once you scroll down scrollbar right side of window user will see more reords append to table as the number of row requests as per page size setting, here I have page size 20.
 
 
 
Once you scroll down then loader will apear under table while getting data from database and disappear once data is appended to table after ajax call is successful. 
 
 

Conclusion

 
In this article we learned about how to implement lazy loading in an MVC application using ajax call and how it helps us to improve performace. This is very important when you have heavy data load. Lazy loading helps us to load data in slots (number of page size) on demand which will bring records when you need or when you scroll down page. This technique leads to a  better user experience and gives better performance due to the fact that ajax call will execute ansyncronously in the backend. 
 
Thank you for reading !!! Happy coding !!!