Reputation: 91
I have a class:
// Person.cs
public class Person
{
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
public double Temperature { get; set; }
public double Pulse { get; set; }
public double Weight { get; set; }
}
I want to create a form that reuses partial forms as components, such as this:
// MyForm.razor
<h1>Currently editing: @Person.Name</h1>
<EditForm EditContext="EditContext">
<PersonDefault />
<PersonHealthStats />
</EditContext>
@code {
private Person Person;
private EditContext? EditContext;
protected override void OnInitialized()
{
EditContext = new(Person);
}
}
How would I go about creating these partial components?
PersonDefault
component should include inputs for the Name
and DateOfBirth
fields.PersonHealthStats
component should include inputs for the Temperature
, Pulse
, and Weight
fields.Person
Name
field is updated, it should sync with the h1 tag.1. Binding Person
to the child component
// MyForm.razor
<PersonDefault @bind-Person="Person" />
// PersonDefault.razor
<input @bind="Person.Name" />
@code {
[Parameter] public Person Person { get; set; }
[Parameter] public EventCallback<Person> PersonChanged { get; set; }
}
This solution works for updating the values on Person
, but doesn't sync with the h1 tag.
2. Binding individual parameters for each field
// MyForm.razor
<PersonDefault @bind-Name="Person.Name" />
// PersonDefault.razor
<input @bind="Name" />
@code {
[Parameter] public EventCallback<string> NameChanged { get; set; }
private string _Name;
[Parameter] public string Name {
get => _Name;
set
{
if (_Name == value) return;
_Name = value;
NameChanged.InvokeAsync(value);
}
}
}
This solution works for updating the values on Person
and syncing the h1 tag, but creates a lot of redundant code the more input fields I add to the component.
EDIT:
I made an image to better illustrate what I'm trying to achieve
Upvotes: 1
Views: 741
Reputation: 91
I decided to revisit solution 1 and was able to get the sync working. Here's my code:
<InputText @bind-Value="Name" />
@code {
[Parameter] public Person Person { get; set; }
[Parameter] public EventCallback<Person> PersonChanged { get; set; }
private Person _Person; // Backing store
private string Name
{
get => _Person.Name;
set
{
if (_Person.Name == value) return;
_Person.Name = value;
InvokePersonChanged();
}
}
protected override void OnInitialized()
{
_Person = new() {
Name = Person.Name
};
}
private void InvokePersonChanged()
{
if (PersonChanged.HasDelegate) PersonChanged.InvokeAsync(_Person);
}
}
Upvotes: 3