Brakkie101
Brakkie101

Reputation: 169

Refresh html table data using Blazor and C#

I have a situation where I have a for loop that creates my html table from my datamodel which gets the data from SQL server express. I would like to know if it is possible to create a auto refresh method where the table data only gets refreshed and not the full page, if not then maybe a method that OnClick button will retrieve the latest data from datamodel and update the table accordingly.

I'm new to blazor and C# so any help would be appreciated, my current page structure currently looks as follows:

@page "/employees"

@using DataLib;

@inject IEmployeeData _db

@if (employees is null)
{
    <p style="color:white;"><em>Loading . . .</em></p>
}
else
{
    <table class="table" id="myTable">
        <thead>
            <tr>
                <th>Entry Date</th>
                <th>Employee</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var employee in employees)
            {
                <tr>
                    <td>@employee.EntryDate</td>
                    <td>@employee.POI</td>
                </tr>
            }
        </tbody>
    </table>
}

@code{
    private List<EmployeeModel> employees;

    protected override async Task OnInitializedAsync()
    {
        employees = await _db.GetEmployee();
    }

}

The above works perfect when I'm loading this page and when I do a manual refresh.

Is there a way that you guys can maybe assist me?

Thanks.

Upvotes: 4

Views: 16268

Answers (5)

Wylde Solutions
Wylde Solutions

Reputation: 1

I have tried the response above (answered Jun 10, 2020 at 15:42) and there's a few issues with it:

  • if it's called like that then there will be an infinite loop of calls and button clicks, because the code in

    protected override async Task OnAfterRenderAsync(bool firstRender) { await JSRuntime.InvokeVoidAsync("EmployeeInterop.refreshEmployeeData"); }

will be called for all component render events which will happen every time the button is clicked.

The code has to be like this:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender) {
      await JSRuntime.InvokeVoidAsync("EmployeeInterop.refreshEmployeeData");
    }
    await base.OnAfterRenderAsync(firstRender);
}

Upvotes: 0

Suprabhat Biswal
Suprabhat Biswal

Reputation: 3216

If your aim is just to refresh the data at regular interval then you can make use of Javascript Interop that is supported by Blazor. The set-up documentation is available in this link.

Like said by Mathias Z in this solution you would need a button for this to work.

I can see you have been writing both C# code and HTML in same file however I personally prefer keeping them separately. Coming back to the solution you can make use to JavaScript and c# to periodically refresh your displayable content.

Below are the changes you need to make to make it work.

Code-Behind

using Microsoft.JSInterop; // import this library

using this you can invoke JavaScript methods.

[Inject]
private IJSRuntime JSRuntime { get; set; }

OnAfterRenderAsync and OnAfterRender are called after a component has finished rendering. Element and component references are populated at this point. Use this stage to perform additional initialization steps using the rendered content, such as activating third-party JavaScript libraries that operate on the rendered DOM elements.

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    await JSRuntime.InvokeVoidAsync("EmployeeInterop.refreshEmployeeData");
}

// This method will be called on button click.
protected async Task GetEmployees()
{
    employees = await _db.GetEmployee();
}

wwwroot

Within this folder we generally keep our web-resources including js libraries. Here, create a javascript file e.g. EmployeeInterop.js and below code.

(function () {
    window.EmployeeInterop = {
        refreshEmployeeData: () => {
            setInterval(() => { 
                document.getElementById("btnGetEmployeeData").click();
            }, 3000);
        }
    };
})();

The setInterval() method calls a function or evaluates an expression at specified intervals (in milliseconds). You can define your own time of refresh.

_Host.cshtml

Register this script file here.

<script src="EmployeeInterop.js"></script>

EmployeeDetail.razor

<button id="btnGetEmployeeData" @onclick="GetEmployees"> Refresh Employee List</button>

Add this below your table tag. In-case you don't want this button to be visible to the end-user then add a style attribute and set it to display:none.

Upvotes: 0

Hunab Ku
Hunab Ku

Reputation: 11

Mathias Z

I not understand why not this answer is not taken for good, but for me is all that i want, StateHasChanged(); because i still not use JavaScript.

    public MyConstructor()
    {
        _My_collection_.CollectionChanged += Change_EventArgs;
    }

    void Change_EventArgs(object sender, EventArgs e) 
    {  
        StateHasChanged();
    } 

Upvotes: 1

Brian Parker
Brian Parker

Reputation: 14623

You could create a SignalR hub on your server. Inject the hub into your api controllers, use it to signal clients that updates have occurred to the data from the API.

Upvotes: 1

Mathias Z
Mathias Z

Reputation: 575

Not sure this is your aim butt you could try;

@inject IEmployeeData _db

@if (employees is null)
{
    <p style="color:white;"><em>Loading . . .</em></p>
}
else
{
    <table class="table" id="myTable">
        <thead>
            <tr>
                <th>Entry Date</th>
                <th>Employee</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var employee in employees)
            {
                <tr>
                    <td>@employee.EntryDate</td>
                    <td>@employee.POI</td>
                </tr>
            }
        </tbody>
    </table>

    <button @onclick="GetEmployees"> Refresh Employee List</button>
}


@code{
    private List<EmployeeModel> employees;

    protected override async Task OnInitializedAsync()
    {
        GetEmployees()

}

    private async void GetEmployees()
    {
        employees.Clear();

        employees = await _db.GetEmployee();

        StateHasChanged();
    }

Good luck,

Upvotes: 5

Related Questions