C
C#2y ago
Ryme

✅ Two-way binding class object Blazor Server

I seem to lack understanding of how to two-way bind a class to a child component that's updating some of the properties of the class. Clicking the Update button will make the value change because StateHasChanged(), but this also makes the all the initialization methods run as well which in my real example is getting some data from a database and would be unnecessary to repeat. I'm guessing this is exepcted behaviour since the object reference doesn't change?
Is there a way to get this working when only exposing a @bind-Value from the child component? What would be the appropriate way to do this?
// Person.cs

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// Person.cs

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
// Index.razor

@page "/"

<h1>Hello, @_person.Name! You are @_person.Age years old.</h1>

<PersonForm @bind-Value="_person" />
<button @onclick="StateHasChanged">Update</button>

@code {
private Person _person = new() { Name = "Joe", Age = 40 };
}
// Index.razor

@page "/"

<h1>Hello, @_person.Name! You are @_person.Age years old.</h1>

<PersonForm @bind-Value="_person" />
<button @onclick="StateHasChanged">Update</button>

@code {
private Person _person = new() { Name = "Joe", Age = 40 };
}
// PersonForm.razor

<EditForm Model="BoundValue">
<InputNumber @bind-Value="BoundValue.Age" />
<InputText @bind-Value="BoundValue.Name" />
</EditForm>

@code {
[Parameter]
public Person Value { get; set; }

[Parameter]
public EventCallback<Person> ValueChanged { get; set; }

private Person BoundValue
{
get => Value;
set => ValueChaged.InvokeAsync(value);
}
}
// PersonForm.razor

<EditForm Model="BoundValue">
<InputNumber @bind-Value="BoundValue.Age" />
<InputText @bind-Value="BoundValue.Name" />
</EditForm>

@code {
[Parameter]
public Person Value { get; set; }

[Parameter]
public EventCallback<Person> ValueChanged { get; set; }

private Person BoundValue
{
get => Value;
set => ValueChaged.InvokeAsync(value);
}
}
5 Replies
friedice
friedice2y ago
What are you trying to do here? If person form is a child edit form component, and on submit of that component you want the updated data from the child component, you can just pass a delegate from parent to child without having to go through two way binding Or you could manually bind value changed to a function on the parent component that does the things you need as well if you want to always have that value updated
Ryme
RymeOP2y ago
If I were to change the type to a string or an int, then the parent component would update automatically through the two-way binding without needing to call StateHasChanged() and thus avoiding running component/page initializers again. Is this behavior based on the reference or pointer being updated? As you pointed out, the example isn't very useful other than for me to try and understand how this works behind the hood. I also tried @bind-Value:event="@(() => Console.WriteLine("Value was updated"))" but this doesn't trigger either which makes me think I don't understand the inner works of it. If you have any insight on how this works and what is "best-practice", I'm glad to hear! Thanks
friedice
friedice2y ago
https://blazor-university.com/components/two-way-binding/ https://www.webassemblyman.com/blazor/blazorbuildrendertree.html https://chrissainty.com/building-components-via-rendertreebuilder/ it's based on how blazor renders components technically. Best practice would be to call StateHasChanged() the least amount, as if your page has a lot of data to render, calling StateHasChanged() can be painfully slow and noticeable
Blazor BuildRenderTree
Blazor BuildRenderTree
Chris Sainty - Building with Blazor
Building Components Manually via RenderTreeBuilder
In this post, I'm going to show you how you can build components manually using Blazors RenderTreeBuilder. Instead of using the traditional Razor syntax approach. I'll also talk about why this shouldn't be your default way of building components.
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Ryme
RymeOP2y ago
Thanks for the info 🙂
Want results from more Discord servers?
Add your server