Asked by:
Blazor does not update interface after calling a method

Question
-
User433211055 posted
I start to learn Blazor
I write this code that call a service to load the data from sql server;
I set the parameter and call a method and this work fine, but it doesn't work the second time the interface does not update.
Why?
Every time I call the method shouldn't the interface be automatically updated ?
In debug mode the service method is called and the data is updated.
This is my code
@page "/ChipsReport" @using Data; @inject ChipsReportService crService <h3>ChipsReport</h3> <input id="txtDate" type="date" required @bind-value="paramChipReport.DataIni" /> <select @bind="paramChipReport.ValueTypeId"> <option value="42">opt1</option> <option value="1">opt2</option> <option value="36">opt3</option> <option value="100">opt4</option> </select> <select @bind="paramChipReport.Absolute"> <option value="0">Inc</option> <option value="1">Tot</option> </select> <button class="btn btn-primary" @onclick="@(() => LoadData(paramChipReport))">Load data</button> <br /> @if (chipReports != null) { <table class="table table-sm table-striped"> <thead> <tr> <th>Test</th> <th>Test1</th> <th>Test2</th> </tr> </thead> <tbody> @foreach (var cr in chipReports) { <tr> <td>@cr.Tag</td> <td>@cr.Time.ToShortDateString()</td> <td>@cr.Pos</td> </tr> } </tbody> </table> } @code { public class ParamChipReport { public DateTime DateIni{ get; set; } public int ValueTypeId { get; set; } public int Absolute { get; set; } }; ParamChipReport paramChipReport = new ParamChipReport(); ChipReport[] chipReports; private async Task<ChipReport[]> LoadData(ParamChipReport paramChipReport) { return chipReports = await crService.GetChipsReports(paramChipReport.GamingDate, paramChipReport.ValueTypeId, paramChipReport.Absolute); } }
BR
Monday, October 5, 2020 4:56 PM
All replies
-
User-474980206 posted
Blazor uses a component tree and virtual dom. while an event will trigger a tree re-render, a component will only re-render if one of its properties (parameter or binding values) has changed since last render.
In you case, you are only updating a local variable on the event, so no render is required.
Anyway, just change chipReport to class property, and make either public or add [Parameter] attribute.
Tuesday, October 6, 2020 1:58 AM -
User433211055 posted
I try but doesn't work.
Blazor uses a component tree and virtual dom. while an event will trigger a tree re-render, a component will only re-render if one of its properties (parameter or binding values) has changed since last render.
In you case, you are only updating a local variable on the event, so no render is required.
Anyway, just change chipReport to class property, and make either public or add [Parameter] attribute.
I update my code but not obtain any bood result
This is my code
ChipReport Page
@page "/ChipsReport" @using Data; @inject ChipsReportService crService <h3>ChipsReport</h3> <input id="txtDate" type="date" required @bind-value="paramChipReport.DataIni" /> <select @bind="paramChipReport.ValueTypeId"> <option value="42">Par </option> <option value="1">Par 2</option> <option value="36">Par 3</option> <option value="100">Par 4</option> </select> <select @bind="paramChipReport.Absolute"> <option value="0">Inc</option> <option value="1">Abs</option> </select> <button class="btn btn-primary" @onclick="@(() => LoadData(paramChipReport))">Load data</button> <br /> <hr /> @if (@chipReports == null) { <h2>Noting</h2> } else { <table class="table table-sm table-striped"> <thead> <tr> <th>Tag</th> <th>Date</th> <th>Total</th> </tr> </thead> <tbody> @foreach (var cr in @chipReports) { <tr> <td>@cr.Tag</td> <td>@cr.DataIni.ToShortDateString()</td> <td>@cr.Total</td> </tr> } </tbody> </table> } @code { public class ParamChipReport { public DateTime DataIni { get; set; } public int ValueTypeId { get; set; } public int Absolute { get; set; } }; public ParamChipReport paramChipReport = new ParamChipReport(); public List<ChipReport> chipReports; private async Task<List<ChipReport>> LoadData(ParamChipReport paramChipReport) { return chipReports = await crService.GetChipsReportsAsync(paramChipReport.DataIni, paramChipReport.ValueTypeId, paramChipReport.Absolute); } }
Method service for data
public async Task<List<ChipReport>> GetChipsReportsAsync(DateTime DataIni, int valueTypeId, int absolute) { var param = new SqlParameter[] { new SqlParameter() {ParameterName = "@dataini", SqlDbType = System.Data.SqlDbType.DateTime, Direction = System.Data.ParameterDirection.Input, Value = gamingDate }, new SqlParameter() {ParameterName = "@valuetypeid", SqlDbType = System.Data.SqlDbType.Int, Direction = System.Data.ParameterDirection.Input, Value = valueTypeId }, new SqlParameter() {ParameterName = "@absolute", SqlDbType = System.Data.SqlDbType.Int, Direction = System.Data.ParameterDirection.Input, Value = absolute} }; chipsReport = await _context .chipsReports .FromSqlRaw("EXECUTE [Accounting].[usp_ChipsReportEx] @dataini, @valuetypeid, @absolute ", param) .ToListAsync(); return chipsReport; }
Anyone can help me to undestand... ??
Exist other approach?
BR
Tuesday, October 6, 2020 11:28 AM -
User-474980206 posted
you really should read the lifecycle, especially events and binding. I believe you need the [Parameter] attribute, as you have no binding expression.
if the [Parameter] doesn't work, the easiest way to force a re-render is to call StateHasChanged().
Tuesday, October 6, 2020 6:35 PM -
User433211055 posted
Hi
I modify my section code in this mode, but doesn't work@code { public class ParamChipReport { public DateTime GamingDate { get; set; } public int ValueTypeId { get; set; } public int Absolute { get; set; } }; public ParamChipReport paramChipReport = new ParamChipReport(); [Parameter] public List<ChipReport> chipReports { get; set; } [Parameter] public EventCallback<List<ChipReport>> ChipReportChanged { get; set; } private async Task LoadData() { chipReports = await crService.GetChipsReportsAsync(paramChipReport.GamingDate, paramChipReport.ValueTypeId, paramChipReport.Absolute); await ChipReportChanged.InvokeAsync(chipReports); } }
BR
And service method
public async Task<List<ChipReport>> GetChipsReportsAsync(DateTime gamingDate, int valueTypeId, int absolute) { var param = new SqlParameter[] { new SqlParameter() { ParameterName = "@gaming", SqlDbType = System.Data.SqlDbType.DateTime, Direction = System.Data.ParameterDirection.Input, Value = gamingDate }, new SqlParameter() { ParameterName = "@valuetypeid", SqlDbType = System.Data.SqlDbType.Int, Direction = System.Data.ParameterDirection.Input, Value = valueTypeId}, new SqlParameter() { ParameterName = "@absolute", SqlDbType = System.Data.SqlDbType.Int, Direction = System.Data.ParameterDirection.Input, Value = absolute } }; return await Task.FromResult( _context .chipsReports .FromSqlRaw("EXEC [Accounting].[usp_ChipsReportEx] @gaming, @valuetypeid, @absolute", param) .ToList() ); }
Friday, October 9, 2020 3:09 PM -
User-474980206 posted
my only guess is that the event handler is confused by the lambda. try:
onclick="@(async (e) => await LoadData())"
or
onclick="LoadData"
and loaddata to:
private async Task LoadData() { chipReports = await crService.GetChipsReportsAsync(paramChipReport.GamingDate, paramChipReport.ValueTypeId, paramChipReport.Absolute); }
Saturday, October 10, 2020 7:55 PM