Closed mquarino closed 3 years ago
I've ran your code (mocking the API call) and it seems to work. Note that I've changed the calls to async/await where possible.
@code {
private PagedResult<TestEntity> _data;
private int _page = 1;
protected override async Task OnInitializedAsync()
{
await LoadTest();
}
private async Task LoadTest()
{
var testList = await Http.GetFromJsonAsync<TestEntity[]>("http://localhost:44348/api/test")
.ConfigureAwait(false);
_data = testList.AsQueryable()
.ToPagedResult(_page, 10);
StateHasChanged();
}
}
Can you send some same code for the API?
In my test, I used
[HttpGet] public TestEntity[] Get()
It's possible with a mix of synchronous and asynchronous calls, the call is returned before the data is populated.
Yes, the API code is this. Basically it connects to a DB and obtains a list of records (no more than 50 rows)
[HttpGet]
[AllowAnonymous]
public async Task<List<Common.TestEntity> Get([FromQuery] PaginationDTO pagination, [FromQuery] string lastName)
{
IOperationsService service = (IOperationsService)this.Provider.GetService(typeof(IOperationsService));
return await service.GetList<Common.TestEntity>();
}
Great, thanks. I suspect the issue is:
OnPageChanged="(async e => { _page = e; LoadTest(); })"
The async call without an await will cause the code to return before LoadPage is done. Just to prove that out, can you change your code to something like this (_mainly changing LoadTest to async and changing the null check to data) :
@page "/test"
@using BlazorPagination
@using System.Text.Json
@inject IJSRuntime js
@inject HttpClient http
<h3>TEST</h3>
@if (_data == null)
{
<p>Loading....</p>
}
else
{
<table data-toggle="table" id="table">
<thead class="font-weight-bold">
<tr>
<th scope="col" data-field="Id" data-sortable="true">Id</th>
<th scope="col" data-field="Text" data-sortable="true">Text</th>
<th scope="col" data-field="Value" data-sortable="true">Value</th>
</tr>
</thead>
<tbody>
@foreach (var t in _data.Results)
{
<tr>
<td scope="row">@t.Id</td>
<td>@t.Text</td>
<td>@t.Value</td>
</tr>
}
</tbody>
</table>
<JSFunction></JSFunction>
<BlazorPager CurrentPage="@_data.CurrentPage"
PageCount="@_data.PageCount"
OnPageChanged="(async e => { _page = e; await LoadTest(); })"
ShowFirstLast="false"
ShowPageNumbers="true"
VisiblePages="10"
FirstText="First"
LastText="Last" />
}
@code {
private PagedResult<Common.TestEntity> _data;
private int _page = 1;
protected override async Task OnInitializedAsync()
{
await LoadTest();
}
async Task LoadTest()
{
var httpResponse = await http.GetAsync($"https://localhost:44348/api/test");
if (httpResponse.IsSuccessStatusCode)
{
var responseString = await httpResponse.Content.ReadAsStringAsync();
var testList = JsonSerializer.Deserialize<List<Common.TestEntity>>(responseString,
new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
_data = testList.AsQueryable().ToPagedResult(_page, 10);
}
else
{
// handle error
}
this.StateHasChanged();
}
}
If that works, then we know where the issue is. If so, then we can add a OnPageChangedAsync
vs OnPageChanged
to allow you to use synchronous methods.
I made the suggested changes but it still doesn't work for me
List<Common.TestEntity> testList;
private PagedResult<Common.TestEntity> _data;
private string _filter;
private int _page = 1;
protected override async Task OnInitializedAsync()
{
await LoadTest();
}
async Task LoadTest()
{
HttpClient http = new HttpClient();
testList = await http.GetFromJsonAsync<List<Common.TestEntity>>($"https://localhost:44348/api/test");
_data = testList.AsQueryable().ToPagedResult(_page, 10);
await InvokeAsync(StateHasChanged);
}
And these parts? The last one being the most important.
@if (**_data** == null)
{
<p>Loading....</p>
}
else
{
...
OnPageChanged="(async e => { _page = e; **await** LoadTest(); })"
Yes, I even tried removing all the async and awaits
page "/test"
@using BlazorPagination
@using System.Net.Http.Json
@inject IJSRuntime js
@inject HttpClient http
<h3>CBU</h3>
<table data-toggle="table" id="table">
<thead class="font-weight-bold">
<tr>
<th scope="col" data-field="Id" data-sortable="true">Id</th>
<th scope="col" data-field="Text" data-sortable="true">Text</th>
<th scope="col" data-field="Value" data-sortable="true">Value</th>
</tr>
</thead>
<tbody>
@foreach (var t in _data.Results)
{
<tr>
<td scope="row">@t.Id</td>
<td>@t.Text</td>
<td>@t.Value</td>
</tr>
}
</tbody>
</table>
<BlazorPager CurrentPage="@_data.CurrentPage"
PageCount="@_data.PageCount"
OnPageChanged="(async e => { _page = e; LoadTest(); })"
ShowFirstLast="false"
ShowPageNumbers="true"
VisiblePages="10"
FirstText="First"
LastText="Last" />
<JSFunction></JSFunction>
@code {
List<Common.TestEntity> testList;
private PagedResult<Common.TestEntity> _data = new PagedResult<Common.TestEntity>();
private string _filter;
private int _page = 1;
protected override void OnInitialized()
{
LoadTest();
}
void LoadTest()
{
testList = http.GetFromJsonAsync<List<Common.TestEntity>>($"https://localhost:44348/api/test").GetAwaiter().GetResult();
_data = testList.AsQueryable().ToPagedResult(_page, 10);
this.StateHasChanged();
}
}
I still see this:
OnPageChanged="(async e => { _page = e; LoadTest(); })"
Can you add the await there? i.e. :
OnPageChanged="(async e => { _page = e; await LoadTest(); })"
To fix that, the we may need to add a synchronous version, but I want to verify that this is the culprit first.
With this change throw a NullReference in the foreach since _data or _data.Results are null
I guess I miss something
@page "/test"
@using BlazorPagination
@using System.Net.Http.Json
@inject IJSRuntime js
@inject HttpClient http
<table data-toggle="table" id="table">
<thead class="font-weight-bold">
<tr>
<th scope="col" data-field="Id" data-sortable="true">Id</th>
<th scope="col" data-field="Text" data-sortable="true">Text</th>
<th scope="col" data-field="Value" data-sortable="true">Value</th>
</tr>
</thead>
<tbody>
@foreach (var t in _data.Results)
{
<tr>
<td scope="row">@t.Id</td>
<td>@t.Text</td>
<td>@t.Value</td>
</tr>
}
</tbody>
</table>
<BlazorPager CurrentPage="@_data.CurrentPage"
PageCount="@_data.PageCount"
OnPageChanged="(async e => { _page = e; await LoadTest(); })"
ShowFirstLast="false"
ShowPageNumbers="true"
VisiblePages="10"
FirstText="First"
LastText="Last" />
<JSFunction></JSFunction>
@code {
List<Common.TestEntity> testList;
private PagedResult<Common.TestEntity> _data = new PagedResult<Common.TestEntity>();
private int _page = 1;
protected override async Task OnInitializedAsync()
{
await LoadTest();
}
async Task LoadTest()
{
testList = await http.GetFromJsonAsync<List<Common.TestEntity>>($"https://localhost:44348/api/test");
_data = testList.AsQueryable().ToPagedResult(_page, 10);
//await InvokeAsync(StateHasChanged);
this.StateHasChanged();
}
}
Looks good, almost there, just add that null check back
@if (_data == null)
{
<p>Loading....</p>
}
else
{
etc ...
}
Still not refreshing the UI
I uploaded up test project here - if you want to take a look: https://github.com/villainoustourist/BlazorPaginationTest
The specific page that I'm testing is here: https://github.com/villainoustourist/BlazorPaginationTest/blob/master/Client/Pages/Index.razor
It sounds like the projects are at least similar - let's check environments. You're using Blazor WASM (I assume based on code - although it works server-side as well), on a current browser (not IE)? I'm running the 3.1.403 version of the .NET Core SDK testing on the Edge browser version 86.
The problem is here. If remove the JSFunction tag, paging works, it only remains for me to see how to implement bootstrap-table
<JSFunction></JSFunction>
ect IJSRuntime jsRuntime
@code{
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await jsRuntime.InvokeVoidAsync(identifier: "test");
}
}
}
<script>
function test() {
$(function () {
$('#table').bootstrapTable()
})
}
</script>
Glad you figured it out. Sometimes JS + Blazor causes some challenges.
Hi, I'm testing the component but I can't get the UI to refresh. I followed the instructions you provide but still I couldn't
I leave you my code to see if you can help me