Search code examples
blazorblazor-server-sideblazor-component

How to pass parameter to component before rendering?


I'm trying to do a simple table with pagination in Blazor server-side.

The table is a Blazor component and the pagination module is another Blazor component. The pagination component (Paginador) has a parameter for the total rows (which is used to calculate the last page in the set).

I can render the table, the pagination section and it updates the table's contents on page change, but for some reason the TotalRows parameter arrives to Paginador with 0 instead of the total rows' value.

Code as follows.

List component:

@page "/personas/listar"

@inject SqlServerPersonasRepository _repo;

<h3>Lista de personas</h3>

<table class="table table-striped">
    <thead>
        <tr>
            <th>DNI</th>
            <th>Nombre</th>
            <th>Apellido</th>
            <th>Fecha de nacimiento</th>
            <th>¿Activo?</th>
            <th>Tipo</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in _personas)
        {
            <tr>
                <td><code>@item.Dni</code></td>
                <td>@item.Nombre</td>
                <td>@item.Apellido</td>
                <td>@item.FechaNacimiento.ToString("dd/MM/yyyy")</td>
                <td>@(item.Activo ? "Sí":"No")</td>
                <td>@item.Tipo.Nombre</td>
            </tr>
        }
    </tbody>
</table>

<div class="row">
    <Paginador TotalRows="_total_rows" OnPageChange="@GetPageAsync" />
</div>

@code {
    [Parameter]
    public int Page { get; set; } = 1;

    private int _total_rows;
    private List<PersonaModel> _personas = new();

    protected override async Task OnInitializedAsync()
    {
        _total_rows = await _repo.ContarAsync();
    }

    protected override async Task OnParametersSetAsync()
    {
        _personas = await _repo.ListarAsync(Page);
    }

    public async Task GetPageAsync(int page)
    {
        _personas = await _repo.ListarAsync(page);
    }
}

Paginador:

@inject IOptions<TablesSettings> Options

<nav aria-label="Page navigation example">
    <ul class="pagination">
        <li class="page-item @(_current_page == 1 ? "disabled": string.Empty)">
            <button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(1))" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
                @*<span class="sr-only">1</span>*@
            </button>
        </li>
        @if (_current_page == 1)
        {
            <li class="page-item disabled"><button type="button" class="page-link">1</button></li>
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(2))">2</button></li>
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(3))">3</button></li>
        }
        else if (_current_page == _last_page)
        {
            var two_to_last = _last_page - 2;
            var one_to_last = _last_page - 1;
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(two_to_last))">@two_to_last</button></li>
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(one_to_last))">@one_to_last</button></li>
            <li class="page-item disabled"><button type="button" class="page-link">@_last_page</button></li>
        }
        else
        {
            var previous = _current_page - 1;
            var next = _current_page + 1;
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(previous))">@previous</button></li>
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(_current_page))">@_current_page</button></li>
            <li class="page-item"><button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(next))">@next</button></li>
        }

        <li class="page-item @(_current_page == _last_page ? "disabled" : string.Empty)">
            <button type="button" class="page-link" @onclick="(async () => await PageChangeAsync(_last_page))" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
                @*<span class="sr-only">@_last_page_index</span>*@
            </button>
        </li>
    </ul>
</nav>

@code {
    [Parameter]
    public int TotalRows { get; set; }
    [Parameter]
    public EventCallback<int> OnPageChange { get; set; }

    private int _current_page { get; set; } = 1;
    private int _last_page;

    protected override async Task OnInitializedAsync()
    {
        _last_page = (int)Math.Ceiling(decimal.Divide(TotalRows, Options.Value.RowsPerPage));
    }

    protected async Task PageChangeAsync(int page)
    {
        await OnPageChange.InvokeAsync(page);
        _current_page = page;
        StateHasChanged();
    }
}

What I've found out is that, when loading the page, Paginador gets rendered before the list component's OnInitializedAsync method is called, so the TotalRows parameter takes a default value.

So, how do I get the total of rows in Paginador before it's rendered?

Thanks in advance.


Solution

  • So, how do I get the total of rows in Paginador before it's rendered?

    Put an @if block around the component expecting the data. – Brian Parker

    Do something like this:

    if (_total_rows > 0 )
    {
       <div class="row">
        <Paginador TotalRows="_total_rows" OnPageChange="@GetPageAsync" />
       </div>
    }
    

    The if statement will now allow the creation of the Paginador component when the total of rows is greater than 0.

    Note: I've read your question very quickly, but I believe this is what you should do:

    protected override async Task OnInitializedAsync()
    {
       // Retrieve the persons list
       _personas = await _repo.ListarAsync(Page); 
        
    }
    
    // Get rid of  OnParametersSetAsync()
    

    And

    <div class="row">
        <Paginador TotalRows="@_personas.Count" OnPageChange="@GetPageAsync" />
    </div>