Forms

🟨 Slightly different to Blazor WebAssembly

Handling user input with forms is the cornerstone of many common applications. Applications use forms to enable users to log in, to update a profile, to enter sensitive information, and to perform many other data-entry tasks. Blazor makes it easy to create and manage them using C#. With Blazor's data binding capabilities, form validation, and other features, you can quickly create dynamic and interactive forms that help users input and submit data. In this tutorial, we'll explore the various aspects of building forms in Blazor and provide you with practical examples to help you get started:

  • Blazor form and HTML form.
  • Create a basic Blazor form.
  • Blazor form validation.
  • Disable a form control.
  • Display validation message.
  • Blazor form events.
  • Blazor form validation styles.
  • Common mistakes.
  • Key differences between Blazor WebAssembly and Blazor Server.
You can download the example code used in this topic on GitHub.

Blazor form and HTML form

EditForm is a component that is used to create forms in Blazor applications, while HTML form is a standard way of creating forms in HTML. The EditForm component in Blazor provides features such as form validation, disabling a form control, and data binding. It allows developers to easily create forms that are tightly integrated with their Blazor application.

blazor-form-vs-html-form.png

Below is a sample code for a Blazor form:

<EditForm Model="BlazorFormModel" OnSubmit="_ => BlazorFormSubmitted = true">
    <fieldset>
        <legend>Blazor form</legend>
        <InputText @bind-Value="BlazorFormModel.BlazorFormResult" />
        <input type="submit" value="Submit" />
    </fieldset>
</EditForm>

And here's a sample code for an HTML form:

<form @onsubmit="_ => HtmlFormSubmitted = true">
    <fieldset>
        <legend>HTML form</legend>
        <input type="text" @bind-value="HtmlFormResult" @bind-value:event="oninput" />
        <input type="submit" value="Submit" />
    </fieldset>
</form>
This tutorial will only cover the Blazor form.

Create a simple Blazor form

To create a basic Blazor form, follow these steps:

  1. Define a form model class that represents the data you want to collect from the user. The form model is an object that stores the information entered by the user. In this example, we'll create a form model that contains a single property of type string:
public class SimpleBlazorFormModel
{
    public string InputText { get; set; } = "Blazor School";
}
  1. In your Blazor component, create a property that references your form model. This property will be used to bind the form fields to the model's properties:
@code {
    public SimpleBlazorFormModel FormModel { get; set; } = new();
}
  1. Use the EditForm component to define the form in your UI. The EditForm component is responsible for managing the form submission and binding the form fields to the model's properties:
<EditForm Model="FormModel" OnSubmit="HandleFormSubmit">
    <InputText @bind-Value="FormModel.InputText" />
    <button>Submit</button>
</EditForm>
  1. Implement the HandleFormSubmit method in your component to handle the form submission:
@code {
    ...
    public void HandleFormSubmit()
    {
        // Do something with the form data
    }
}

Blazor form validation

As a programmer, validation is a crucial task that you cannot ignore, especially when it comes to website development. It's essential to validate user input to ensure that the data you receive is correct and safe to use. In Blazor Server forms, validation is performed in the server and you don't need to implement another layer of validation. There are two types of validation that you can use:

  • Static Data Validation: This type of validation is performed against predefined rules or constraints. For example, you might validate that an email address is in the correct format or that a password meets certain complexity requirements. Blazor provides several built-in validation attributes that you can use, such as Required, StringLength, and RegularExpression.

  • Dynamic Data Validation: This type of validation is performed against dynamic data that changes at runtime. For example, you might validate that a username is unique or that a credit card number is valid by calling an external service. Blazor provides a way to implement custom validation logic using the ValidationMessage and ValidationMessage<T> components, which can display error messages based on your custom validation logic.

By using a combination of these two validation types, you can ensure that your Blazor forms collect correct and valid data from users, and prevent errors and security issues.

Static data validation

In Blazor form, you can use DataAnnotation to validate data against static rules like length, pattern, and range. Here are the steps to validate data against static rules using DataAnnotation:

  1. Define a form model class and specify validation rules for each property using DataAnnotation attributes. 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 ExampleString property has the [Required] attribute which specifies that it must have a value, while the ExampleInt property has the [Range] attribute which specifies the minimum and maximum values it can have.

  1. Declare the form model and bind it to the Model property of the EditForm component. Also, add a submit button. For example:
<EditForm Model="FormModel">
    <button>Submit</button>
</EditForm>

@code {
    public AgainstStaticDataFormModel FormModel { get; set; } = new();
}
  1. Add the DataAnnotationsValidator component inside the EditForm component. For example:
<EditForm Model="FormModel">
    <DataAnnotationsValidator />
    ...
</EditForm>
  1. (Optional) Display error messages using the ValidationMessage or ValidationSummary components.

Here's a list of the available DataAnnotation attributes that you can use for validating 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.

Dynamic data validation

EditContext and ValidationMessageStore are the two primary components used for data validation. EditContext facilitates control over the validation flow, while ValidationMessageStore enables the addition of validation messages to the entire form or specific form controls. To validate data against dynamic business logic, follow these steps:

  1. Declare properties for each of the EditContext, form model, and ValidationMessageStore in the code section:
@code {
    public EditContext FormContext { get; set; } = null!;
    public AgainstDynamicDataFormModel FormModel { get; set; } = new();
    public ValidationMessageStore ValidationMessageStore { get; set; } = null!;
}
Note: Using null! will help ignore the dereference warning in Visual Studio 2022, but it doesn't safeguard against null references. Always exercise caution when using null!.
  1. Initialize the declared properties in the OnInitialized phase:
protected override void OnInitialized()
{
    FormContext = new(FormModel);
    ValidationMessageStore = new(FormContext);
}
  1. Define the validation flow in the method with the signature object? sender, FieldChangedEventArgs e:
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();
}

The validation flow involves removing old validation results, executing custom validation code, and running static data validation. To add a validation message, use ValidationMessageStore.Add() and pass in the field. To add a validation message to the entire form, specify the field as <YourEditContext>.Field(string.Empty).

  1. Subscribe to the OnFieldChanged event of EditContext, and unsubscribe when necessary:
@implements IDisposable

...

@code {
    ...
    protected override void OnInitialized()
    {
        ...
        FormContext.OnFieldChanged += OnFormContextFieldChanged;
    }

    public void Dispose()
    {
        FormContext.OnFieldChanged -= OnFormContextFieldChanged;
    }
}

By following these steps, you can implement dynamic data validation in Blazor forms with ease, ensuring data accuracy and integrity in complex business logic scenarios.


Disable a form control

Disabling form controls is a common requirement for many websites, especially when certain users need to be prevented from interacting with specific parts of a form based on their roles. There are two ways to disable form controls in Blazor.

Method 1: Use the HTML disabled attribute

Using this method will permanently disable the form control. To do this, simply add the disabled attribute with a value of true to the control. For example:

<InputText class="form-control" @bind-Value="FormModel.ExampleString" disabled="true" />

Method 2: Use the Blazor @bind-disabled directive

Using this method, the form control can be dynamically switched between enabled and disabled states. To do this, declare a boolean 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="DisableFormControl"/>

@code {
    public bool DisableFormControl { get; set; } = false;
    ...
}

Whenever you change the boolean value, the form control will be enabled or disabled accordingly.


Display validation message

Validation messages are essential in ensuring that users provide the correct inputs in a form. In order to effectively communicate validation errors to users, there are two places to display validation messages: validation summaries and inline validation messages.

validation-summary-vs-validation-form-control.png

A validation summary displays all validation errors in a form, and can be implemented using the ValidationSummary component. To use this component, simply add it within the EditForm element:

<EditForm Model="FormModel">
    <DataAnnotationsValidator />
    <ValidationSummary />
    ...
</EditForm>

Inline validation messages, on the other hand, are displayed next to the form control that has an error. To display inline validation messages, use the ValidationMessage component. To implement inline validation messages, add the ValidationMessage component immediately after the corresponding form control. Here's an example:

<EditForm Model="FormModel">
    <ValidationSummary />
    <InputText @bind-Value="FormModel.ExampleString" />
    <ValidationMessage For="() => FormModel.ExampleString" />
</EditForm>

When using the ValidationMessage component, it's important to specify the For parameter, which should be followed by a delegate that returns the corresponding form model property.


Blazor form events

Blazor forms have three events that you can handle: OnSubmit, OnValidSubmit, and OnInvalidSubmit. Understanding how to handle these events can help you validate user inputs and provide a better user experience.

Here's what each event does:

  • OnSubmit: This event is fired when the user clicks the submit button. Blazor form will let you handle the validation. You can choose to implement your own validation logic or use static data to validate the form.

  • OnValidSubmit: This event is fired when the user clicks the submit button and the form has passed validation against static data. You can use this event to perform additional validation or make changes based on the validated form data.

  • OnInvalidSubmit: This event is fired when the user clicks the submit button and the form has failed validation against static data. You can use this event to perform additional validation or make changes based on the invalidated form data.

Handling these events is similar, you just need to bind the event with an event handler. Here's an example of handling the OnValidSubmit event:

<EditForm Model="FormModel" OnValidSubmit="ValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />
    ...
    <button>Submit</button>
</EditForm>

@code {
    ...
    public void ValidSubmit(EditContext formContext)
    {
    }
}

In this example, the ValidSubmit method is called when the form has passed validation against static data. You can modify the method to suit your validation logic, and you can remove the EditContext parameter if you don't need it.


Blazor form validation styles

When it comes to website development, there are two commonly used form validation styles: inline validation and after submission validation.

  • Inline validation: In this style, validation occurs in real-time as the user makes changes to the form. For instance, if a form requires an email and phone number, inline validation will check if the email is valid as soon as the user moves to the next input field after entering the email.
  • After submission validation: In this style, validation happens only after the user submits the form. For instance, if a form requires an email and phone number, the user would have to enter both pieces of information and then click the submit button, after which validation errors would be displayed (if any).

By default, Blazor forms do not support after submission validation.


Common mistakes

When working with Blazor forms, there are some common mistakes that should be avoided. These include:

  • Modifying the form control value without notifying the field change.
  • Creating a function button instead of a submit button.
  • Forgetting to use the DataAnnotationsValidator tag.

Modifying the form control value without notifying the field change

If you need to modify a form control value for some reason, it's important to notify the field change to ensure that the validations run again. In the following code, the incorrect way of updating the FormModel.RequiredString value is shown:

<EditForm EditContext="FormContext">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputText @bind-Value="FormModel.RequiredString" />
    <button type="button" @onclick="Correct">Correct</button>
    <button type="button" @onclick="Mistake">Mistake</button>
</EditForm>

@code {
    public void Mistake()
    {
        FormModel.RequiredString = "";
    }
}

To correctly update the FormModel.RequiredString value, you need to notify the field change as shown below:

public void Correct()
{
    FormModel.RequiredString = "";
    FormContext.NotifyFieldChanged(FormContext.Field(nameof(FormModel.RequiredString)));
}

By not notifying the field change, you run the risk of accepting incorrect information since the validations are not run again. The following video demonstrates this mistake in action.

Creating a function button instead of a submit button

To ensure clarity in button functionality, it is important to differentiate between submit buttons and function buttons. Submit buttons are used to send form data to a server while function buttons are used to execute some logic without submitting the form.

To create a function button, you can use either the <button type="button"> tag or <input type="button"> tag. Correct submit buttons can be created using the <button> tag or the <input type="submit"> tag.

Examples of correct function buttons include:

<input type="button" @onclick="Method1" value="Call Method" />
<button type="button" @onclick="Method1" value="">Call Method</button>

Examples of correct submit buttons include:

<button>Submit</button>
<input type="submit" value="Submit" />

However, it is important to note that some buttons may unintentionally call a method and submit the form at the same time. This can be problematic and should be avoided. Examples of incorrect buttons that call the method and submit the form at the same time include:

<button @onclick="Method1">(Not Intended) Call Method & Submit (button tag)</button>
<input type="submit" @onclick="Method1" value="(Not Intended) Call Method & Submit (input tag)" />

To avoid this mistake, it is important to carefully consider the type and functionality of each button when creating them. The following video demonstrates this common mistake and the importance of distinguishing between function buttons and submit buttons.

Forgetting to use the DataAnnotationsValidator tag

The DataAnnotationsValidator tag is a crucial component for validating forms when using the EditForm component. Its absence can result in the failure of form validation. To illustrate this point, please refer to the following video.


Key differences between Blazor WebAssembly and Blazor Server

In Blazor WebAssembly, form validation occurs on the client-side. Therefore, it's necessary to perform additional validation on the API side. Alternatively, you could delegate all validation processes to the API and import errors to the form, as demonstrated in the Dynamic Data Validation section.

In contrast, Blazor Server handles form validation on the server-side, which eliminates the need for additional API-side validation.

BLAZOR SCHOOL
Designed and built with care by our dedicated team, with contributions from a supportive community. We strive to provide the best learning experience for our users.
Docs licensed CC-BY-SA-4.0
Copyright © 2021-2024 Blazor School
An unhandled error has occurred. Reload 🗙