Blazor Forms and Validation

This week I’m exploring the basics of using forms and validation in a server-side Blazor. This is an area that the Blazor team is still making a lot of changes too so don’t be surprised if some of the things in this post need to be tweaked. If you need help creating a Blazor application check out my ASP.NET Core Server-Side Blazor with Authentication post, which is the app I’m using to write this post.

Model

For this example, I’m going to be creating a form for editing a contact. Blazor will make use of data annotations and automatically make sure that the conditions are valid. The following is the class I’m using as my model with a few data annotations thrown in. Project structure-wise I added a Models directory and added my model class there.

public class Contact
{
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    [StringLength(5, 
                  MinimumLength = 5, 
                  ErrorMessage = "Postal Code must be 5 characters")]
    public string PostalCode { get; set; }
    public string Phone { get; set; }
    [Required]
    [EmailAddress]
    public string Email { get; set; }
}

As you can see in the class Name and Email are both required fields. Email is also required to be a valid email address. PostalCode isn’t required, but if entered must be 5 characters. If the Postal Code is entered but isn’t 5 characters then the specified error message will show in the UI.

Component

Next, I added a new ContactEdit component. For details on how to add a new component check out Razor Components in Blazor which will walk through adding a new component using Visual Studio. It will also show you have to add the component to an existing page.

The following is the full component. Most of the component is normal HTML form elements. After the code, I will point a few things out.

@using Models
@using System.Diagnostics

<h3>Contact Edit</h3>

<div class="row">
    <div class="col-md-4">
        <EditForm Model="@contact" OnValidSubmit="@ValidSubmit">
            <DataAnnotationsValidator />
            <ValidationSummary />

            <div class="form-group">
                <label for="name" class="control-label">Name: </label>
                <InputText id="name" @bind-value="contact.Name" class="form-control" />
                <ValidationMessage For="@(() => contact.Name)" />
            </div>
            <div class="form-group">
                <label for="address" class="control-label">Address: </label>
                <InputText id="address" @bind-value="contact.Address" class="form-control" />
                <ValidationMessage For="@(() => contact.Address)" />
            </div>
            <div class="form-group">
                <label for="city" class="control-label">City: </label>
                <InputText id="city" @bind-value="contact.City" class="form-control" />
                <ValidationMessage For="@(() => contact.City)" />
            </div>
            <div class="form-group">
                <label for="state" class="control-label">State: </label>
                <InputText id="state" @bind-value="contact.State" class="form-control" />
                <ValidationMessage For="@(() => contact.State)" />
            </div>
            <div class="form-group">
                <label for="postalCode" class="control-label">Postal Code: </label>
                <InputText id="postalCode" @bind-value="contact.PostalCode" class="form-control" />
                <ValidationMessage For="@(() => contact.PostalCode)" />
            </div>
            <div class="form-group">
                <label for="phone" class="control-label">Phone: </label>
                <InputText id="phone" @bind-value="contact.Phone" class="form-control" />
                <ValidationMessage For="@(() => contact.Phone)" />
            </div>
            <div class="form-group">
                <label for="email" class="control-label">Email: </label>
                <InputText id="email" @bind-value="contact.Email" class="form-control" />
                <ValidationMessage For="@(() => contact.Email)" />
            </div>
            <button type="submit">Submit</button>
        </EditForm>
    </div>
</div>

@code {
    private Contact contact = new Contact
    {
        Id = 1,
        Name = "Eric",
        Address = "578 Main St.",
        City = "Nashville",
        State = "TN",
        Phone = "615-555-5555",
        Email = "ericeric.com"
    };

    private void ValidSubmit()
    {
        Debug.WriteLine("ValidSubmit");
    }
}

The following is a subsection of the code from above that is different from standard HTML forms.

<EditForm Model="@contact" OnValidSubmit="@ValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <div class="form-group">
        <label for="name" class="control-label">Name: </label>
        <InputText id="name" @bind-value="contact.Name" class="form-control" />
        <ValidationMessage For="@(() => contact.Name)" />
    </div>
    <button type="submit">Submit</button>
</EditForm>

The EditForm is a component that Microsoft created that will bind to your model and allow you to specify what function is going to be called on submit. In this example, we are using OnValidSubmit to call the ValidSubmit function only if the model validates. Make note of the usage of the DataAnnotationsValidator which is the component that enables validation based on the data annotations that we placed on our model class.

The other thing to note is the usage of the ValidationSummary component which shows a summary of all the validation issues on the model. This example is also using ValidationMessage to show errors in line with the associated fields. In a real application, I doubt both would be used, but I wanted to show how to use both.

Wrapping Up

Hopefully, this has been a helpful introduction to forms and validation in Blazor. I may end up doing a follow-up post on the other submission options.

Make sure and check out the official docs for more information.  Rémi Bourgarel also has a great post on the subject.


Also published on Medium.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.