Reputation: 19
I'm having problem using HstateHasChanged in Blazor, I want to rerender the Categories component every time when I add a new category. This is the code that I was expecting to work:
MyCategories.razor
@page "/categories"
@inject IModalService Modal
@inject ICategoryService CategoryService
@implements IDisposable
<div class="col-md-8 col-sm-12 col-xs-12 ">
<button @onclick="@(()=>Modal.Show<AddCategory>("New Category"))" class="btn btn-primary">Add New</button>
@if (CategoryService.Categories == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Title</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var category in CategoryService.Categories)
{
<tr>
<td>@category.Title</td>
<td><a href="#" class="btn btn-danger">Remove</a></td>
</tr>
}
</tbody>
</table>
}
</div>
@code {
protected override async Task OnInitializedAsync()
{
CategoryService.OnChange += StateHasChanged;
await CategoryService.LoadCategoriesAsync();
}
public void Dispose()
{
CategoryService.OnChange -= StateHasChanged;
}
}
MyAddCategory.razor here I have created this component and call it in the categories. I have called this component in the categories.razor, and it will show a form in a modal.
@inject NavigationManager NavigationManager
@inject IToastService ToastService
@inject ICategoryService CategoryService
@implements IDisposable
<EditForm Model="category" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator></DataAnnotationsValidator>
<div class="form-group">
<label for="title" class="required">Title</label>
<InputText id="title" @bind-Value="category.Title" class="form-control"></InputText>
<ValidationMessage For="@(()=>category.Title)" />
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</EditForm>
@code {
private Category category = new Category();
public void Dispose()
{
CategoryService.OnChange -= StateHasChanged;
}
async void HandleSubmit()
{
var result= await CategoryService.AddCategoryAsync(category);
if (result.Success)
{
CategoryService.OnChange += StateHasChanged;
ToastService.ShowSuccess(result.Message);
NavigationManager.NavigateTo("/categories");
}
else
{
ToastService.ShowError("An error has occured.");
}
}
}
Upvotes: 2
Views: 143
Reputation: 30410
Let's take a lok at your code:
async void HandleSubmit()
{
var result= await CategoryService.AddCategoryAsync(category);
if (result.Success)
{
CategoryService.OnChange += StateHasChanged;
ToastService.ShowSuccess(result.Message);
NavigationManager.NavigateTo("/categories");
}
So you add a category with await CategoryService.AddCategoryAsync(category);
. Does this raise CategoryService.OnChange
? It should.
You register an event handler in the modal CategoryService.OnChange += StateHasChanged;
and then immediately navigate away from ther page with NavigationManager.NavigateTo("/categories");
In MyCategories
you get the CategoryService.Categories
on initialization, but I see no where where you refresh the list.
protected override async Task OnInitializedAsync()
{
CategoryService.OnChange += StateHasChanged;
await CategoryService.LoadCategoriesAsync();
}
You just call StateHasChanged
(if CategoryService.OnChange
is raised).
In the code you've shown us, the dots aren't joined up.
Adding a category should cause the category service to raise the OnChange
event, and either any listeners should refresh CategoryService.Categories
or it should refresh automatically on the add/delete/update.
Upvotes: 1