Reputation: 2993
In a Blazor form, I'd like to be able to detect whenever a form value has changed, and set a boolean value as a result.
Here is some code to illustrate how I am currently doing it:
<EditForm Model="Person" OnValidSubmit="OnSubmitValidateForm">
<div class="form-group">
<label>First Name</label>
<input type="text" value="@Person.FirstName" @onchange="OnFirstNameChanged" />
</div>
<div class="form-group">
<label>Surname</label>
<input type="text" value="@Person.Surname" @onchange="OnSurnameChanged" />
</div>
<input type="submit" class="btn btn-primary" value="Save"/>
</EditForm>
@code {
Person Person = new Person();
bool dataChanged = false;
void OnFirstNameChanged(ChangeEventArgs e)
{
Person.FirstName = e.Value.ToString();
dataChanged = true;
StateHasChanged();
}
void OnSurnameChanged(ChangeEventArgs e)
{
Person.Surname = e.Value.ToString();
dataChanged = true;
StateHasChanged();
}
}
In the above form I have two fields - "FirstName" and "Surname" which are properties of the "Person" class. There is an input textbox bound to each property. Whenever the value changes in either textbox, the respective method is called which will update the property value, and also indicate that the form data has changed.
It seems excessive to have an event handler for every form item, when in each case all it's really doing is what @bind="" would do, plus setting dataChanged to true.
My question is, whilst the approach works, it seems like I have to write quite a lot of extra code. Is there a better way to handle this?
Upvotes: 8
Views: 14525
Reputation: 688
You must use EditContext instead of Model in your EditForm. Sample:
<EditForm EditContext="PersonContext" OnValidSubmit="@OnSubmitValidateForm">
<div class="form-group">
<label>First Name</label>
<input type="text" @bind-value="person.FirstName" />
</div>
<div class="form-group">
<label>Surname</label>
<input type="text" @bind-value="person.Surname" />
</div>
<input type="submit" class="btn btn-primary" value="Save" />
</EditForm>
@code {
EditContext PersonContext;
Person person = new Person();
protected override void OnParametersSet()
{
PersonContext = new(person);
}
void OnSubmitValidateForm()
{
if (PersonContext.IsModified())
{
//you logic
}
}
}
Upvotes: 2
Reputation: 45596
You should use the native Forms Components, such as InputText, InputDate, etc., and implement the OnFieldChanged
event. The OnFieldChanged event is raised for each field in the model.
Code sample
@page "/"
@using Microsoft.AspNetCore.Components.Forms;
<EditForm EditContext="@ValidationContext.EditContext"
OnValidSubmit="HandleValidSumit">
<DataAnnotationsValidator />
<div class="form-group">
<label for="name">FirstName: </label>
<InputText Id="FirstName" Class="form-control" @bind-
Value="@person.FirstName"></InputText>
<ValidationMessage For="@(() => person.FirstName)" />
</div>
<div class="form-group">
<label for="body">Surname: </label>
<InputText Id="body" Class="form-control" @bind-
Value="@person.Surname"></InputText >
<ValidationMessage For="@(() => person.Surname)" />
</div>
<button type="submit" class="btn btn-success">Submit</button>
</EditForm>
@code
{
Person person = new Person();
protected override void OnInitialized()
{
EditContext = new EditContext(person);
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
base.OnInitialized();
}
private async Task HandleValidSumit()
{
Console.WriteLine("Saving...");
Console.WriteLine(person.FirstName);
Console.WriteLine(Person.Surname);
}
// Note: The OnFieldChanged event is raised for each field in the
// model
private void EditContext_OnFieldChanged(object sender,
FieldChangedEventArgs e)
{
Console.WriteLine(e.FieldIdentifier.FieldName);
}
}
Note: Calling the StateHasChanged
() method from event handlers for UI events such as Click
, Change
, etc. is superfluous. It is automatically called by the framework.
Upvotes: 12