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

  1. CRUD Using Blazor, Entity Framework Core And Dapper
  2. Sorting Table In Blazor

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.

  1. skip: How many records we want to skip.
  2. take: How many records we want to take from the database.
  3. orderBy: On which column you want to sort records. (necessary to use skip and take functionality.)
  4. 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 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.

Footer Logo

Subscribe

Select Categories