Why the Blazor UI doesn't update after delete event:
My Component:
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Example</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var trainingTechnique in TrainingTechniques) {
<tr>
<td>@trainingTechnique.Id</td>
<td>@trainingTechnique.Name</td>
<td>@trainingTechnique.Example</td>
<td>
<button type="button"
class="btn btn-danger"
@onclick="@(async () => await DeleteTechnique(trainingTechnique.Id))">
Delete
</button>
</td>
</tr>
}
</tbody>
</table>
My Component code behind:
public class TrainingTechniqueViewPageBase : ComponentBase
{
public List<TrainingTechniqueView> TrainingTechniques { get; set; }
[Inject]
public ITrainingTechniqueConsumer TrainingTechniqueConsumer { get; set; }
protected TrainingTechniqueForm TrainingTechniqueForm { get; set; }
protected override async Task OnInitializedAsync()
{
TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
}
public async void TrainingTechniqueForm_OnSave()
{
TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
StateHasChanged();
}
protected void AddTrainingTechnique()
{
TrainingTechniqueForm.Show();
}
protected async Task DeleteTechnique(int id)
{
await (TrainingTechniqueConsumer.DeleteTrainingTechnique(id));
this.StateHasChanged();
}
}
}
The Delete Method:
public async Task DeleteTrainingTechnique(int id)
{
await _httpClient.DeleteAsync($"training/trainingtechniques/{id}");
}
Component initialization ( OnInitialized{Async} ) Blazor apps that prerender their content on the server call OnInitializedAsync twice: Once when the component is initially rendered statically as part of the page. A second time when the browser renders the component.
If a component implements IDisposable, the Dispose method will be called when the component is removed from the UI. You can use Dispose method to release unmanaged resources, unhook events, dispose DotNetObjectReference instances to avoid memory leak. Refer to the following code sample.
Platform: Blazor Category: General. The StateHasChanged is a method in ComponentBase that notifies state changes to a component.
Solution 1: Reload the TrainingTechniques list from the source
private async Task Delete(int id)
{
await TrainingTechniqueConsumer.DeleteTrainingTechnique(id);
TrainingTechniques = (await TrainingTechniqueConsumer.GetTechniques()).ToList();
}
Solution 2: Remove the item form the list:
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Example</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var trainingTechnique in TrainingTechniques)
{
<tr>
<td>@trainingTechnique.Id</td>
<td>@trainingTechnique.Name</td>
<td>@trainingTechnique.Example</td>
<td>
<button type="button" class="btn btn-danger" @onclick="@(() => DeleteTechnique(trainingTechnique.Id))">Delete</button>
</td>
</tr>
}
</tbody>
</table>
And the Delete method:
private async Task Delete(int id)
{
TrainingTechniques.RemoveAll(x => x.Id == Id);
await TrainingTechniqueConsumer.DeleteTrainingTechnique(id);
}
Remove the item from the list that has the binding to the UI.
protected async Task DeleteTechnique(int id)
{
await (TrainingTechniqueConsumer.DeleteTrainingTechnique(id));
TrainingTechniques.Remove(TrainingTechniques.Single(x => x.Id == id));
}
I think it is better to pass the item it self instead of an Id. For example the delete could be:
protected async Task DeleteTechnique(TrainingTechniqueView corpse)
{
await (TrainingTechniqueConsumer.DeleteTrainingTechnique(corpse.Id));
TrainingTechniques.Remove(corpse);
}
I had the same problem and almost same UI as yours but my problem was instead of defining TrainingTechniques as List, I'd defined it as IEnumerable. So instead of:
public IEnumerable<TrainingTechniqueView> TrainingTechniques { get; set; }
I changed it as:
public List<TrainingTechniqueView> TrainingTechniques { get; set; }
And then using one of solutions suggested by @Inktkiller.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With