Reputation: 11614
I have built a web assembly blazor project.
In one of its blazor components, there is a Form to submit new data.
This form, POST the data to server via a web api to save in database.
<EditForm Model="@person">
<div class="col-12 row">
<label class="col-2 font-weight-bold">Id : </label>
<InputNumber class="form-control col-3" @bind-Value="person.Id" placeholder="id" />
</div>
<br />
<div class="col-12 row">
<label class="col-2 font-weight-bold">Name : </label>
<InputText class="form-control col-3" @bind-Value="person.Name" placeholder="name" />
</div>
<input type="submit" class="form-control btn btn-primary text-center" @onclick="@AddPerson" value="Add" />
</EditForm>
The C# code behind @AddPerson
is this :
@code
{
public List<Person> people;
public Person person = new Person();
private async void AddPerson()
{
HttpResponseMessage httpResponse = await Http.PostAsJsonAsync<Person>("https://apisite.ir/api/people", person);
people = await Http.GetFromJsonAsync<List<Person>>("https://apisite.ir/api/people");
}
}
The people list is being shown in such a table in a foreach like this :
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
</tr>
</thead>
<tbody>
@foreach (Person p in people)
{
<tr>
<td>@p.Id</td>
<td>@p.Name</td>
</tr>
}
</tbody>
</table>
The problem is that, when I click Add button , both api call happen, BUT nothing in the UI changes.
The table which suppose to show list of people would not update.
What should I do ?
Upvotes: 1
Views: 2055
Reputation: 45626
You shouldn't do this:
<input type="submit" class="form-control btn btn-primary text-center" @onclick="@AddPerson" value="Add" />
Instead you should do this:
<button type="submit">Submit</button>
The role of the "submit" button is to 'submit' the form data to the server, which should never occurs, which is why I use the word submit with single quotation marks. And you should not apply the @onclick
directive to the "submit" button. Instead, you should use the OnValidSubmit
event attribute of the EditForm like this:
<EditForm Model="@person" OnValidSubmit="AddPerson">
Now, when the user hit the "submit" button, the Blazor framework intercepts the submission action and cancels it (no form submission in SPA applications), and if your model passes validation( as for instance, Person.Name must not be longer than 50 characters ), then the AddPerson method is invoked...
In the early development stages of Blazor, you had to use the StateHasChanged method in code that requires re-rendering. Currently, the StateHasChanged method is called by default from UI event handlers.
When you define your method as asynchronous yet returning void (async void)
your UI is never refreshed (re-rendered) because the StateHasCahnged is never being called by the runtime, as the runtime can never know when the async methods called return, and thus the execution of the AddPerson method ends without calling the StateHasCahnged method. When you use async Task
, the Task object let the runtime know that the awaited method has returned, the result of which: the runtime calls the StateHasCahnged method to notify the relevant component that its state has changed and that it should re-render... Always use async Task
Upvotes: 4
Reputation: 11614
I searched about this, and every where was saying to add StateHasChanged();
after calling my API's as answer.
The problem is misleading but I solve it just by changing void to Task
private async Task AddPerson()
{
HttpResponseMessage httpResponse = await Http.PostAsJsonAsync<Person>("https://apisite.ir/api/people", person);
people = await Http.GetFromJsonAsync<List<Person>>("https://apisite.ir/api/people");
}
I don't know why this happens because I'm not good in writing async/await code, and I found this by chance !
I posted this here to help others to get rid of StateHasChanged();
if they are having same situation.
Upvotes: 8