4

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.

5
  • 1
    Also, take a look here: c-sharpcorner.com/blogs/using-ajax-in-asp-net-mvc Commented Jun 8, 2020 at 22:32
  • 3
    If refreshing on a timed schedule is sufficient you can use a timer. That example does a navigation, but you can just refresh your data instead of navigate. If you need to refresh the data immediately when the database is updated then that's more complicated but possible. Commented Jun 8, 2020 at 23:37
  • 1
    @Paedow This question isn't a duplicate of the linked question. Blazor works completely differently to the way suggested in the answer. Please could you re-open this question so I can answer it correctly? Commented Jun 9, 2020 at 8:20
  • 1
    @Paedow Please re-open this, the answer you propose is entirely unrelated to the OP's question. Commented Jun 9, 2020 at 13:38
  • Sorry, I was not aware that it would be immediately closed. I flagged it as a possible duplicate, that's all. Commented Jun 9, 2020 at 17:40

5 Answers 5

5

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,

Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

1

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();
    } 

Comments

0

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.

Comments

0

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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.