Form is a good way to collect user information. Blazor Server has a built-in form with rich features. In this tutorial, you will discover:
You can download the example code used in this topic on GitHub.
Both Blazor Server form and HTML share the same purpose: collect user's information. However, they are different in terms of use and support in Blazor Server. The following image illustrates the differences between Blazor Form and HTML form:
A sample Blazor Server form:
<EditForm Model="BlazorFormModel" OnSubmit="_ => BlazorFormSubmitted = true"> <fieldset> <legend>Blazor form</legend> <InputText @bind-Value="BlazorFormModel.BlazorFormResult" /> <input class="btn btn-primary" type="submit" value="Submit" /> </fieldset> </EditForm>
A sample HTML form:
<form @onsubmit="_ => HtmlFormSubmitted = true"> <fieldset> <legend>HTML form</legend> <input type="text" @bind-value="HtmlFormResult" @bind-value:event="oninput" /> <input class="btn btn-primary" type="submit" value="Submit" /> </fieldset> </form>
This tutorial will only focus on Blazor Server form.
To create a basic Blazor Server form, you need to:
public class BasicBlazorFormModel { public string ExampleString { get; set; } = "Blazor School"; }
@code { public BasicBlazorFormModel FormModel { get; set; } = new(); }
EditForm
component in the UI section to display your form. You must also pass the FormModel
to the component. For example:<EditForm Model="FormModel" OnSubmit="SubmitForm"> <InputText @bind-Value="FormModel.ExampleString" /> </EditForm>
<EditForm Model="FormModel" OnSubmit="SubmitForm"> ... <button class="btn btn-primary">Submit</button> </EditForm> @code { ... public void SubmitForm() { } }
Validation is a crucial task for programmers. In the world of website development, never trust a user input. Form validation is the process of checking if the information provided by a user is correct. In Blazor Server form, if the validation is written in C#, it will be executed in the server whereas if it is written in JavaScript, it will be executed in the browser. There are 2 kinds of validation:
Blazor Server form uses DataAnnotation
to validate against static data like the length, the pattern of a string, a number in range. To validating data against static data, you need to:
DataAnnotation
. For example:public class AgainstStaticDataFormModel { [Required] public string ExampleString { get; set; } = ""; [Range(2, int.MaxValue, ErrorMessage = "This is a custom message.")] public int ExampleInt { get; set; } = 1; }
In the above example, the property ExampleString
has the [Required]
attribute which will specify the ExampleString
must have a value. The property ExampleInt
has the [Range]
attribute which will specify the minimum and the maximum number for ExampleInt
, in this case the ExampleInt
must have value from 2 to the int.MaxValue
; Any value that is not in the range will display the error message "This is a custom message".
<EditForm Model="FormModel"> <button class="btn btn-primary">Submit</button> </EditForm> @code { public AgainstStaticDataFormModel FormModel { get; set; } = new(); }
DataAnnotationsValidator
tag inside the EditForm
. For example:<EditForm Model="FormModel"> <DataAnnotationsValidator /> ... </EditForm>
ValidationMessage
or ValidationSummary
.This is the list of DataAnnotation
attributes for validate data.
Attribute Name | Description |
---|---|
Compare |
Compares two properties. |
CreditCard |
Check if the data is a well-formed credit card. |
EmailAddress |
Validates an email address. |
EnumDataType |
Check if the provided data belongs to an enum. |
FileExtensions |
Validates file name extensions. |
MaxLength |
Specifies the maximum length of array or string data allowed in a property. |
MinLength |
Specifies the minimum length of collection/string data allowed in a property. |
Phone |
Specifies that a data field value is a well-formed phone number. |
Range |
Specifies the numeric range constraints for the value of a data field. |
RegularExpression |
Regular expression validation attribute. |
Required |
Validation attribute to indicate that a property field or parameter is required. |
StringLength |
Validation attribute to assert a string property, field or parameter does not exceed a maximum length. |
Url |
Provides URL validation. |
This kind of validation usually benefits complex business logic. Some examples are: check if username is unique, check if there is enough money in the bank account, etc... Blazor Server form uses EditContext
and ValidationMessageStore
, EditContext
will help you to control the validation flow, ValidationMessageStore
will allow you to add a validation message to the entire form or a specific form control. To validating data against dynamic data, you need to:
EditContext
, form model, ValidationMessageStore
in the code section. For example:@code { public EditContext FormContext { get; set; } = null!; public AgainstDynamicDataFormModel FormModel { get; set; } = new(); public ValidationMessageStore ValidationMessageStore { get; set; } = null!; }
Thenull!
will help you to ignore the dereference warning of Visual Studio 2022. However, it does not protect you against null reference. You need to pay attention whenever you usenull!
.
OnInitialized
phase. For example:protected override void OnInitialized() { FormContext = new(FormModel); ValidationMessageStore = new(FormContext); }
object? sender, FieldChangedEventArgs e
. For example:public void OnFormContextFieldChanged(object? sender, FieldChangedEventArgs e) { ValidationMessageStore.Clear(); if (FormModel.AllowText is false && string.IsNullOrEmpty(FormModel.Text) is false) { ValidationMessageStore.Add(FormContext.Field(nameof(FormModel.Text)), "This message is for the field!"); ValidationMessageStore.Add(FormContext.Field(string.Empty), "This message is for the entire form!"); } FormContext.Validate(); }
To add a validation message, you need to useValidationMessageStore.Add()
and pass in the field. In case you want to add a validation message to the entire form, you need to specify the field as<YourEditContext>.Field(string.Empty)
.
OnFieldChanged
of EditContext
and unsubscribe afterward. For example:@implements IDisposable ... @code { ... protected override void OnInitialized() { ... FormContext.OnFieldChanged += OnFormContextFieldChanged; } public void Dispose() { FormContext.OnFieldChanged -= OnFormContextFieldChanged; } }
Having parts of a disabled is a common requirement for any large website. Sometimes, a user must be prevented from interacting with a form based upon their roles on the website. There are 2 ways to disable a form control in Blazor Server form.
disabled
attribute.disabled
directive.By applying this method, your form control is permanently disabled. Assuming you have the following form control:
<InputText class="form-control" @bind-Value="FormModel.ExampleString" />
Then you need to add disabled="true"
to the form control. For example:
<InputText class="form-control" @bind-Value="FormModel.ExampleString" disabled="true" />
By applying this method, your form control can be switched from enabled to disabled. Assuming you have the following form control:
<InputText class="form-control" @bind-Value="FormModel.ExampleString" />
Then you need to declare a bool
property in the component and bind it to the form control using the @bind-disabled
directive. For example:
<InputText class="form-control" @bind-Value="FormModel.ExampleString" @bind-disabled="DisableFormControl2"/> @code { public bool DisableFormControl2 { get; set; } = false; ... }
Then whenever you change the boolean value, the form control will be enabled or disabled accordingly.
There are 2 places to display the validation message, you can either display the validation summary or the validation message for each form control.
The validation summary usually displays all the validation error in your form. You can use the component ValidationSummary
to display the validation summary. For example:
<EditForm Model="FormModel"> <DataAnnotationsValidator /> <ValidationSummary /> <div> <label> Example string: <InputText @bind-Value="FormModel.ExampleString" /> </label> </div> <div> <label> Example number (must be greater than 2): <InputNumber @bind-Value="FormModel.ExampleInt" /> </label> </div> <button class="btn btn-primary">Submit</button> </EditForm>
The inline validation message displays all the validation messages for one and only one form control. You can use the component ValidationMessage
to display the validation message for a specific form control. For example:
<EditForm Model="FormModel"> <ValidationSummary /> <div> <label> Example string: <InputText @bind-Value="FormModel.ExampleString" /> </label> </div> <ValidationMessage For="() => FormModel.ExampleString" /> <div> <label> Example number (must be greater than 2): <InputNumber @bind-Value="FormModel.ExampleInt" /> </label> </div> <ValidationMessage For="() => FormModel.ExampleInt" /> <button class="btn btn-primary">Submit</button> </EditForm>
When using the ValidationMessage
component, you must specify the For
parameter followed by a delegate that returns your form model property.
A Blazor Server form has 3 events: OnSubmit
, OnValidSubmit
and OnInvalidSubmit
.
OnSubmit
: Fired when the user press submit button, Blazor Server form will leave you do the validation.OnValidSubmit
: Fired when the user press the submit button and the form is passed the validation against static data. You can validate your form again and change the validation result here.OnInvalidSubmit
: Fired when the user press the submit button and the form is failed the validation against static data. You can validate your form again and change the validation result here.Handling the Blazor Server form events is similar. Here is an example of handling OnValidSubmit
events.
<EditForm Model="FormModel" OnValidSubmit="ValidSubmit"> <DataAnnotationsValidator /> <ValidationSummary /> <label> Leave textbox empty to make validation error: <InputText @bind-Value="FormModel.ExampleString" /> </label> <button>Submit</button> </EditForm> @code { ... public void ValidSubmit(EditContext formContext) { } }
In the example, in the ValidSubmit
method, you can remove the EditContext
parameter in case you don't need it.
In the website development, there are 2 validation styles for form: inline validation and after submission validation.
However, Blazor Server form does not support after submission validation by default. We will have a guide about this topic later in the Advanced Blazor Server tutorial series.
When working with Blazor Server form, there are some common mistakes that you need to avoid. They are:
DataAnnotationsValidator
tag.For some reasons, you need to modify a form control value but you don't notify the field change. Assuming you have the following code:
<EditForm EditContext="FormContext"> <DataAnnotationsValidator /> <ValidationSummary /> <label> Leave textbox empty to make validation error: <InputText @bind-Value="FormModel.RequiredString" /> </label> <button type="button" class="btn btn-outline-success" @onclick="Correct">Correct</button> <button type="button" class="btn btn-outline-danger" @onclick="Mistake">Mistake</button> </EditForm>
This is not a correct way to update FormModel.RequiredString
.
public void Mistake() { FormModel.RequiredString = ""; }
To update the FormModel.RequiredString
correctly, you need to notify field change afterward.
public void Correct() { FormModel.RequiredString = ""; FormContext.NotifyFieldChanged(FormContext.Field(nameof(FormModel.RequiredString))); }
Whenever you modify a form control value, the validations should run again. When you update the form control value and not notifying field change, the validations are not run, giving you a posibility to accept wrong information. The following video demonstrate this mistake:
A function button is a button to execute some logic but not to submit the form. There are 2 ways to create a button, by using <button>
tag and <input type="button">
tag. These are correct submit buttons:
<button>Submit (button tag)</button> <input type="submit" value="Submit (input tag)" />
These are correct function buttons:
<input type="button" @onclick="Method1" value="Call Method (input tag)" /> <button type="button" @onclick="Method1" value="">Call Method (button tag)</button>
These buttons are not correct buttons because it will call the method and submit the form at the same time:
<button @onclick="Method1">(Not Intended) Call Method & Submit (button tag)</button> <input type="submit" @onclick="Method1" value="(Not Intended) Call Method & Submit (input tag)" />
The following video demonstrates this mistake:
DataAnnotationsValidator
tagThe DataAnnotationsValidator
is an important component when you are using EditForm
component. Without this tag, you cannot validate the form. The following video demonstrates this situation: