Reputation: 41
I try to update a list of objects when I update an object from a form component. But event if my object is well updated, my list is not.
Here my parent component
@inject ApiClient Api
@if (normes != null)
{
<ul>
@foreach (var item in normes)
{
<li @onclick="@(()=> norme = item)">@item.Name</li>
}
</ul>
}
@if (norme != null)
{
<label>The bind parameter in the parent: @norme.Name</label>
<Edit @bind-Norme="norme" />
}
@code {
private List<Norme> normes { get; set; }
private Norme norme { get; set; }
protected override async Task OnInitializedAsync()
{
normes = await Api.GetAsync<List<Norme>>("norme");
}
}
I get a list from an api and when I select a Norme à display a form component to edit it.
Here my child component:
@inject ApiClient Api
<Loader WaitFor="localNorme">
<EditForm Model="localNorme" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator />
@if (localNorme.Id == 0)
{
<h3>Nouvelle norme</h3>
}
else
{
<h3>Norme n° @localNorme.Id</h3>
}
<div class="btn-toolbar justify-content-end" role="toolbar">
<div class="btn-group mr-2" role="group">
<button type="submit" class="btn btn-outline-success"><i class="bi-save" /></button>
<button type="button" class="btn btn-outline-danger" @onclick="OnCancelClick"><i class="bi-x" /></button>
</div>
</div>
<div class="overflow-auto">
<div class="form-group">
<FormLabel For="@(()=>localNorme.Name)" />
<InputText @bind-Value="localNorme.Name" class="form-control" />
<ValidationMessage For="@(()=>localNorme.Name)" />
</div>
<input type="hidden" @bind-value="localNorme.Id" />
</div>
</EditForm>
<label>The bind parameter in the child: @Norme.Name</label>
</Loader>
@code {
[Parameter] public Norme Norme { get; set; }
[Parameter] public EventCallback<Norme> NormeChanged { get; set; }
private Norme localNorme;
protected override async Task OnParametersSetAsync()
{
await LoadAsync();
}
private async Task LoadAsync()
{
if (Norme.Id > 0)
{
localNorme = await Api.GetAsync<Norme>($"norme/{Norme.Id}");
}
else
{
localNorme = new Norme();
}
}
private async Task OnValidSubmit(EditContext context)
{
Norme model = context.Model as Norme;
if (model.Id > 0)
{
// Update
model = await Api.PutAsync<Norme>($"norme/{Norme.Id}", model);
}
else
{
// Create
model = await Api.PostAsync<Norme>("norme", model);
}
await NormeChanged.InvokeAsync(model); // bound object update
}
private async Task OnCancelClick()
{
await LoadAsync();
}
}
Here the result when I have submitted my form:
As you can see, my list is not updated.
At 1st, in my child component I used my Norme parameter as model in my form. But my parent parameter and List were updated on my input's OnChanged event. So I insert a localNorme as model in my form and when it's submit I use the EventCallback to update the bound parameter. In my parent, my parameter is well updated but I don't know what I miss to fire my List update.
I try to insert some StateHasChanged() but nothing changed. I also check if my List is updated if I update a norme's property in the parent.
Thank you.
Upvotes: 1
Views: 1513
Reputation: 9019
Your list you want to update is "normes" I think.
You set that list here:
protected override async Task OnInitializedAsync()
{
normes = await Api.GetAsync<List<Norme>>("norme");
}
Which is only called when the parent is first added to the render tree.
You need a method of updating it when an item has been changed.
The simple way would be to manually bind the Edit component so you can register a handler for the NormeChanged callback
<Edit Norme="norme" NormeChanged=RefreshList/>
And then RefreshList can update the list "normes" and refresh the parent component
async Task RefreshList(Norme norme)
{
normes = await Api.GetAsync<List<Norme>>("norme");
StateHasChanged();
}
Of course there are many ways to do this - centralised state, event aggregator, message bus - this is the simplest to show here.
Upvotes: 2