In this article, we are going to add pagination to the table. In my previous article, I walked through CRUD Using Blazor, Entity Framework Core And Dapper and Sorting Table In Blazor. If you haven’t read yet please read both articles first in order to understand this article. You can download the CRUD Blazor code from here. If you are new to Blazor, I recommend reading Getting Started With Blazor.
Prerequisite
In the previous post, we have done with sorting logic. so we are continuing from there.
Let’s start!
Open “Articlemanager.cs” class and add Count() method.
public Task<int> Count() { var totArticle = Task.FromResult(_dapperManager.Get<int>("select COUNT(*) from [Article]", null, commandType: CommandType.Text)); return totArticle; }
Modify “ListAll()” method for pagination logic.In this method, we will pass four parameters.
- skip: How many records we want to skip.
- take: How many records we want to take from the database.
- orderBy: On which column you want to sort records. (necessary to use skip and take functionality.)
- direction: Order direction either “DESC” or “ASC”.
Our old SQL query was “select * from [Article]”, now we want to make some records and skip some records base on page click. To make this possible modify the select query as below.
select * from [Article] ORDER BY {orderBy} {direction} OFFSET {skip} ROWS FETCH NEXT {take} ROWS ONLY; ", null, commandType: CommandType.Text)); return articles;
“ListAll()” Method will look like this after modification.
public Task<List<Article>> ListAll(int skip, int take, string orderBy, string direction = "DESC") { var articles = Task.FromResult(_dapperManager.GetAll<Article> ($"select * from [Article] ORDER BY {orderBy} {direction} OFFSET {skip} ROWS FETCH NEXT {take} ROWS ONLY; ", null, commandType: CommandType.Text)); return articles; }
Open the “IArticleManager” interface and add the following line and update ListAll method().
Task<int> Count(); Task<List<Article>> ListAll(int skip, int take, string orderBy, string direction);
We have done with business logic, let modify the razor component.
Open the “FetchArticle.razor” page and replace the following code.
@page "/articlelist" @using BlazorCRUD.Entities @using BlazorCRUD.Contracts @inject IArticleManager articleManager <link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <style> .sort-th { cursor: pointer; } .fa { float: right; } .btn-custom { color: black; float: left; padding: 8px 16px; text-decoration: none; transition: background-color .3s; border: 2px solid #000; margin: 0px 5px 0px 5px; } </style> <div> <a class="btn btn-primary" href='/addArticle'>Add</a> </div> <br /> @if (articleModel == null) { <p><em>Loading...</em></p> } else { <table class="table table-bordered table-hover"> <thead> <tr> <th class="sort-th" @onclick="@(() => SortTable("ID"))"> ID <span class="fa @(SetSortIcon("ID"))"></span> </th> <th class="sort-th" @onclick="@(() => SortTable("Title"))"> Title <span class="fa @(SetSortIcon("Title"))"></span> </th> <th>Action</th> </tr> </thead> <tbody> @foreach (var article in articleModel) { <tr> <td>@article.ID</td> <td>@article.Title</td> <td> <a class="btn btn-primary" href='/editArticle/@article.ID'>Edit</a> | <a class="btn btn-danger" @onclick="() => DeleteArticle(article.ID)">Delete</a> </td> </tr> } </tbody> </table> <div class="pagination"> <button class="btn btn-custom" @onclick=@(async ()=>await NavigateToPage("previous"))>Prev</button> @for (int i = startPage; i <= endPage; i++) { var currentPage = i; <button class="btn btn-custom pagebutton @(currentPage==curPage?"btn-danger":"")" @onclick=@(async () =>await refreshRecords(currentPage))> @currentPage </button> } <button class="btn btn-custom" @onclick=@(async ()=>await NavigateToPage("next"))>Next</button> </div> } @code { List<Article> articleModel; Article articleEntity = new Article(); #region Pagination int totalPages; int totalRecords; int curPage; int pagerSize; int pageSize; int startPage; int endPage; string sortColumnName = "ID"; string sortDir = "DESC"; #endregion protected override async Task OnInitializedAsync() { //display total page buttons pagerSize = 3; pageSize = 2; curPage = 1; articleModel = await articleManager.ListAll((curPage - 1) * pageSize, pageSize, sortColumnName, sortDir); totalRecords = await articleManager.Count(); totalPages = (int)Math.Ceiling(totalRecords / (decimal)pageSize); SetPagerSize("forward"); } protected async Task DeleteArticle(int id) { await articleManager.Delete(id); articleModel = await articleManager.ListAll((curPage - 1) * pageSize, pageSize, sortColumnName, sortDir); } private bool isSortedAscending; private string activeSortColumn; private async Task<List<Article>> SortRecords(string columnName, string dir) { return await articleManager.ListAll((curPage - 1) * pageSize, pageSize, columnName, dir); } private async Task SortTable(string columnName) { if (columnName != activeSortColumn) { articleModel = await SortRecords(columnName, "ASC"); isSortedAscending = true; activeSortColumn = columnName; } else { if (isSortedAscending) { articleModel = await SortRecords(columnName, "DESC"); } else { articleModel = await SortRecords(columnName, "ASC"); } isSortedAscending = !isSortedAscending; } sortColumnName = columnName; sortDir = isSortedAscending ? "ASC" : "DESC"; } private string SetSortIcon(string columnName) { if (activeSortColumn != columnName) { return string.Empty; } if (isSortedAscending) { return "fa-sort-up"; } else { return "fa-sort-down"; } } public async Task refreshRecords(int currentPage) { articleModel = await articleManager.ListAll((currentPage - 1) * pageSize, pageSize, sortColumnName, sortDir); curPage = currentPage; this.StateHasChanged(); } public void SetPagerSize(string direction) { if (direction == "forward" && endPage < totalPages) { startPage = endPage + 1; if (endPage + pagerSize < totalPages) { endPage = startPage + pagerSize - 1; } else { endPage = totalPages; } this.StateHasChanged(); } else if (direction == "back" && startPage > 1) { endPage = startPage - 1; startPage = startPage - pagerSize; } } public async Task NavigateToPage(string direction) { if (direction == "next") { if (curPage < totalPages) { if (curPage == endPage) { SetPagerSize("forward"); } curPage += 1; } } else if (direction == "previous") { if (curPage > 1) { if (curPage == startPage) { SetPagerSize("back"); } curPage -= 1; } } await refreshRecords(curPage); } }
Tada! we have done all the things.
It’s time to run application and you will get below output.
You can download the source code from here.
If you want to learn File Upload in Blazor please visit here.
I hope you guys found something useful. Please give your valuable feedback/comments/questions about this article. Please let me know how you like and understand this article and how I could improve it.
Hello,
After Delete buttons numbers not refresh
Hiya, I’m really glad I have found this information. Today bloggers publish just about gossips and web and this is actually frustrating. A good website with exciting content, this is what I need. Thanks for keeping this web site, I’ll be visiting it. Do you do newsletters? Can’t find it.
Thanks for the feedback, sure we will soon update newsletter.
THANKS FAISAL. YOUR ARTICLE HAS BEEN VERY HELPFUL ESPECIALLY AS YOU ARE USING SQL STORED PROCEDURES TO IMPLEMENT INSERT| AND UPDATE . PLS IN YOUR NEXT ARTICLE,
PLS CAN YOU ADD FILTERING BY TYPING A FILTERING TEXT AND EXPORTING THE FILTERED PAGE TO MICROSOFT EXCEL.
THANX FOR ALWAYS USING SQL SERVER STORED PROCEDURES.
Thanks for reading, Sure I’ll