Home > Enterprise >  Persisting data between events in Razor Class Library control
Persisting data between events in Razor Class Library control

Time:04-03

I am trying to create a Razor Class Library (RCL), which I can then use as a reusable set of controls in my Blazor Server app. The RCL control is a table that includes pagination and sorting of columns. The data flow for the control is that the Blazor app handles all the data request and then passed the data to the RCL control. The RCL control handles UI events (next/previous pagination) and the display of the records. The issue I have is that the current page count (which gets updated when the user clicks next or previous page) does not persist between events, so the count never changes. How can I persist the data across events (I am hoping to keep track of ui events within the RCL control and not in the Blazor app using the control). Here is my code (abbreviated):

Razor Class Library Control:

@if (employeeModels == null)
{
    <p><em>Loading...</em></p>
}
else
{
   //table with data ...
   //controls to handle pagination
   <div >
    <button  @onclick=@(async ()=>await NavigateToPage("previous"))>Prev</button>
    @for (int i = startPage; i <= endPage; i  )
    {
        var currentPage = i;
        <button btn-danger":"")" @onclick=@(async () =>await refreshRecords(currentPage))>
            @currentPage
        </button>
    }
    <button  @onclick=@(async ()=>await NavigateToPage("next"))>Next</button>
</div>
}
@code {
    [Parameter]
    public List<EmployeesModel> employeeModels { get; set; }
    [Parameter]
    public EventCallback<bool> RefreshDataEvent { get; set; }
    int totalPages;
    int totalRecords;
    [Parameter]
    public int TotalNumRecords { get; set; }
    [Parameter]
    public int curPage { get; set; }
    [Parameter]
    public int pagerSize{ get; set; }
    [Parameter]
    public int pageSize { get; set; }
    int startPage;
    int endPage;
    [Parameter]
    public string sortColumnName { get; set; } = "LastName";
    [Parameter]
    public string sortDir { get; set; } = "DESC";

    protected override void OnParametersSet()
    {

        base.OnParametersSet();
        totalRecords = TotalNumRecords;
        totalPages = (int)Math.Ceiling(totalRecords / (decimal)pageSize);
        SetPagerSize("forward");        
    }
    public async Task refreshRecords(int currentPage)
    { 
        curPage = currentPage;
        await RefreshDataEvent.InvokeAsync(true);
        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);
    }
}

Blazor App Using Control:

<SortablePaginatedEmployeeTable  
    employeeModels="@employees" 
    curPage="@paginationCurrentPage" 
    pageSize="@paginationPageSize" 
    pagerSize="@paginationPagerSize" 
    sortColumnName="@paginationSortColumnName" 
    sortDir="@paginationSortDirection" 
    RefreshDataEvent="EmployeeListRefrshed" 
    @ref="EmployeeTableControl" 
    TotalNumRecords="@totalNumbEmployees" 
    GotToPageEven="EmployeeNextClick"  >
</SortablePaginatedEmployeeTable>

@code {
    private SortablePaginatedEmployeeTable EmployeeTableControl;
    int paginationCurrentPage = 1;
    int paginationPageSize = 3;
    int paginationPagerSize = 3;
    string paginationSortColumnName = "LastName";
    string paginationSortDirection = "Desc";
    int totalNumbEmployees = 0;

    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        await EmployeeListRefrshed();
    }
    
    private async Task EmployeeListRefrshed()
    {
        all_employees = await _db.ListAllEmployees((EmployeeTableControl.curPage - 1) * paginationPageSize, paginationPageSize, paginationSortColumnName, paginationSortDirection);
        totalNumbEmployees = _db.CountNumberEmployees();
        foreach(var e in all_employees)
        {
            employees.Add(new EmployeesModel { Email = e.Email, FirstName = e.FirstName, LastName = e.LastName, Id = e.Id, PhoneNumber = e.PhoneNumber });
        }
    }

}

With this code, when the user clicks Next the NavigateToPage function gets called but it always returns 2. I believe this is because the data is not persisting between button presses? How can I resolve this?

CodePudding user response:

Your problem is in updating a Parameter in a Component. It's basically a NONO. Read them, use them, but never modify them.

When you trigger RefreshDataEvent it calls EmployeeListRefrshed which gets the data. This updates employees. When the EmployeeListRefrshed completes the component re-renders. This includes triggering a re-render of SortablePaginatedEmployeeTable. paginationCurrentPage is still set to 1 so the component re-renders on page 1.

You need to do something like:

Component

[Parameter]
    public EventCallback<int> RefreshDataEvent { get; set; }

    public async Task refreshRecords(int currentPage)
    { 
        await RefreshDataEvent.InvokeAsync(currentPage);
        // probably not needed
        this.StateHasChanged();
    }

Page

    
    private async Task EmployeeListRefrshed(int pageNo)
    {
        all_employees = await _db.ListAllEmployees((pageNo - 1) * paginationPageSize, paginationPageSize, paginationSortColumnName, paginationSortDirection);
        totalNumbEmployees = _db.CountNumberEmployees();
        foreach(var e in all_employees)
        {
            employees.Add(new EmployeesModel { Email = e.Email, FirstName = e.FirstName, LastName = e.LastName, Id = e.Id, PhoneNumber = e.PhoneNumber });
        }
        this.pagingationcurrentpage = pageNo 
    }
  • Related