ASP.Net Core Blazor ships some great components to get building web forms quickly and easily. The EditForm component allows us to manage forms, validations, and form submission events.
Microsoft docs says, an EditForm "Renders a form element that cascades an EditContext
to descendants."
Let's see a Blazor EditForm in action,
<EditForm Model="@employee" OnValidSubmit="@OnValidSubmit">
<label>Employee Name :</label>
<div>
<InputText @bind-Value="@employee.EmployeeName" />
</div>
<label>Gender :</label>
<div>
<InputSelect @bind-Value="@employee.Gender">
<option value="Select">--Select--</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</InputSelect>
</div>
<label>DOB :</label>
<div>
<InputDate @bind-Value="@employee.DateOfBirth" />
</div>
<label>Department :</label>
<div>
<select @bind="@employee.DepartmentID">
<option value=0>--Select--</option>
<option value=1>Admin</option>
<option value=2>HR</option>
<option value=3>Payroll</option>
</select>
</div>
<button type="submit" class="btn btn-success">
@ButtonText
</button>
</EditForm>
@code {
[Parameter]
public Employee employee { get; set; }
[Parameter]
public string ButtonText { get; set; } = "Save";
[Parameter]
public EventCallback OnValidSubmit { get; set; }
}
If we run this application in the browser you can see the rendered form with all other elements,
<form>
<label>Employee Name :</label>
<div>
<input class="valid">
</div>
<label>Gender :</label>
<div>
<select class="valid">
<option value="Select">--Select--</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</select>
</div>
<label>DOB :</label>
<div>
<input type="date" class="valid">
</div>
<label>Department :</label>
<div>
<select>
<option value="0">--Select--</option>
<option value="1">Admin</option>
<option value="2">HR</option>
<option value="3">Payroll</option>
</select>
</div>
<button type="submit" class="btn btn-success">
Create Employee
</button>
</form>
Here, The EditForm
renders an HTML form element with InputText
as input type=text
, InputSelect
as select
and, InputDate
as input type=date
. Also notice that EditForm added a CSS class 'valid' to each input element. This has something to do with the validation.
You can also use any HTML elements like input
, select
etc. in EditForm as it renders an HTML form.
EditForm Properties
In our example, EditForm
has two attributes specified. Model
and OnValidSubmit
.
Model - Specifies the top-level model object for the form. Let me explain this,
Under the hood, EditForm manages the state of the form and any validation errors by storing it in an EditContext
object. EditForm component instantiates EditContext for the model object specified in the Model attribute. In the above example employee
object.
We can also specify the EditContext
explicitly to an EditForm component by using the EditContext attribute instead of the Model attribute.
<EditForm EditContext="@EmployeeContext" OnSubmit="@OnSubmit">
</EditForm>
Here, we have to explicitly instantiate EditContext
for employee
object
@code {
[Parameter]
public Employee employee { get; set; }
protected EditContext EmployeeContext { get; set; }
protected override void OnInitialized()
{
EmployeeContext = new EditContext(employee);
}
[Parameter]
public string ButtonText { get; set; } = "Save";
[Parameter]
public EventCallback OnSubmit { get; set; }
}
You can specify either a Model or EditContext but not both
Use the Model attribute to specify the form model object and it is sufficient to manage all standard form operations and validations. Use EditContext attribute only if you want to take more direct control over the form's EditContext
object to explicitly fire a validation or to notify a field change etc.
Another attribute used in our example is OnValidSubmit. This is a callback/method that will be invoked when the form is submitted and the EditContext is determined to be valid. In addition to this, EditForm provides two other callback attributes,
OnSubmit callback will be invoked when the form is submitted, but here we have to explicitly validate the EditContext.
OnInValidSubmit callback will be invoked when the form is submitted and the EditContext is determined to be invalid.
Form Validations
We can enable validation for the entire form simply by adding the <DataAnnotationsValidator />
component.
<EditForm Model="@employee" OnValidSubmit="@OnValidSubmit">
<DataAnnotationsValidator />
</EditForm>
The validation will work according to the DataAnnotations specified in our model class properties
public class Employee
{
public int EmployeeID{get;set;}
[Required]
public string EmployeeName{get;set;}
[Range(typeof(DateTime), "1/1/1970", "12/31/2000", ErrorMessage = "Value for {0} must be between {1} and {2}")]
public DateTime DateOfBirth{get;set;}
public Gender Gender{get;set;}
public int DepartmentID{get;set;}
public Department Department{get;set;}
}
With this [Required] attribute we’ve indicated that the user must enter an Employee Name and with the [Range] attribute we have specified the date range that should be entered.
We can show the validation summary by simply adding the <ValidationSummary />
component or you can show the validation message for each input by using the <ValidationMessage >
component
Styling
You can style EditForm simply by adding a CSS class as normal. The form elements will be styled accordingly.
Let's see our example EditForm with all validation and styles added,
<EditForm Model="@employee" OnValidSubmit="@OnValidSubmit">
<DataAnnotationsValidator />
<div class="form-group">
<label>Employee Name :</label>
<div>
<InputText @bind-Value="@employee.EmployeeName" class="form-control col-sm-3" />
<ValidationMessage For="@(() => employee.EmployeeName)" />
</div>
</div>
<div class="form-group ">
<div>
<label>Gender :</label>
<div>
<InputSelect @bind-Value="@employee.Gender" class="form-control col-sm-3">
<option value="Select">--Select--</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</InputSelect>
<ValidationMessage For="@(() => employee.Gender)" />
</div>
</div>
</div>
<div class="form-group ">
<div>
<label>DOB :</label>
<div>
<InputDate @bind-Value="@employee.DateOfBirth" class="form-control col-sm-3" />
<ValidationMessage For="@(() => employee.DateOfBirth)" />
</div>
</div>
</div>
<div class="form-group ">
<div>
<label>Department :</label>
<div>
<select @bind="@employee.DepartmentID" class="form-control col-sm-3">
<option value=0>--Select--</option>
<option value=1>Admin</option>
<option value=2>HR</option>
<option value=3>Payroll</option>
</select>
<ValidationMessage For="@(() => employee.DepartmentID)" />
</div>
</div>
</div>
<button type="submit" class="btn btn-success">
@ButtonText
</button>
</EditForm>
@code {
[Parameter]
public Employee employee { get; set; }
[Parameter]
public string ButtonText { get; set; } = "Save";
[Parameter]
public EventCallback OnValidSubmit { get; set; }
}
Now when you run this in the browser, you can see our form elements nicely styled up. Submit the form to see the validation in action
And, the rendered HTML
<form>
<div class="form-group">
<label>Employee Name :</label>
<div>
<input class="form-control col-sm-3 invalid">
<div class="validation-message">The EmployeeName field is required.</div>
</div>
</div>
<div class="form-group ">
<div>
<label>Gender :</label>
<div>
<select class="form-control col-sm-3 modified valid">
<option value="Select">--Select--</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
<option value="Other">Other</option>
</select>
</div>
</div>
</div>
<div class="form-group ">
<div>
<label>DOB :</label>
<div>
<input type="date" class="form-control col-sm-3 invalid">
<div class="validation-message">Value for DateOfBirth must be between 1/1/1970 0:00:00 and 12/31/2000 0:00:00</div>
</div>
</div>
</div>
<div class="form-group ">
<div>
<label>Department :</label>
<div>
<select class="form-control col-sm-3">
<option value="0">--Select--</option>
<option value="1">Admin</option>
<option value="2">HR</option>
<option value="3">Payroll</option>
</select>
</div>
</div>
</div>
<button type="submit" class="btn btn-success">
Create Employee
</button>
</form>
If you look closely at the rendered HTML, you will notice the extra classes added by EditForm, 'valid', 'invalid' and, 'modified'. The class 'invalid' indicates that it's failed in form validation. You can add CSS style to this class for highlighting the invalid elements. In our example, bootstrap is doing this for us. For any modified element, a 'modified' CSS class will be added.
Summery
EditForm is pretty useful in creating web forms that keep the values in your model in sync with the values entered in the UI with out of the box validation support. But it doesn't stop you from creating your own form components in Blazor and implement custom logic for validations. EditForm is designed in such a way that you can easily implement any form validation you like. if you don't want to use DataAnnotation you can use any available validation components like FluentValidation
or write a custom validation component.
If you wish to see how to use this Blazor EditForm in a working example, please read my previous post Blazor Server CRUD App Using Visual Studio Code. You can find the sample application source code here
Top comments (0)