DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Build a Dynamic Web Form Using Camunda BPMN and DMN
  • Automating a Web Form With Playwright MCP and MySQL MCP
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes
  • Dynamic Web Forms In React For Enterprise Platforms

Trending

  • Amazon Quick: AWS's Agentic Workspace, Explained for Engineers
  • A Spring Boot App With Half the Startup Time
  • Persistent Memory for AI Agents Using LangChain's Deep Agents
  • Is the Data Warehouse Dead? 3 Patterns From Enterprise Architecture That Answer This Question

Blazor Form Validation

Introducing form validation with Blazor and .NET Core 3.0.

By 
Gunnar Peipman user avatar
Gunnar Peipman
·
Aug. 19, 19 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
24.2K Views

Join the DZone community and get the full member experience.

Join For Free

Client-side Blazor supports DataAnnotations form validation out-of-the-box. It’s simple and intuitive but also very flexible. If needed, we can use the same mechanism to replace DataAnnotations validation with some other validation component. This blog post introduces form validation in Blazor applications and looks at an engine of validation mechanism.

Form validation in Blazor is experimental and subject to changes. This blog post is written using .NET Core 3.0 Preview 7.

Data Annotations Validation

Blazor supports DataAnnotations validation out-of-the-box. To use validation we have to have model with data annotations and edit form defined in Blazor view.

Let’s create a simple model for a guestbook. It has properties for poster name and message.

public class GuestbookEntry 
 {    
   [Required]    
   [MaxLength(10)]    
   public string Name { get; set; }     
  
   [Required]    
   public string Text { get; set; }
}


Here is a Blazor form that uses out-of-the-box form validation. I followed the same pattern with validation messages that should be familiar, at least with those who know ASP.NET MVC.

@page "/"
@using  BlazorFormValidation.Models 

<h1>My guestbook</h1> 

<p>Leave me a message if you like my site</p> 

<EditForm Model="@Model" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit">    
  <div class="alert @StatusClass">@StatusMessage</div>        
  
  <DataAnnotationsValidator />    
  <ValidationSummary />        
  
  <div class="form-group">        
    <label for="name">Name: </label>        
    <InputText Id="name" Class="form-control" @bind-Value="@Model.Name"></InputText>        
    <ValidationMessage For="@(() => Model.Name)" />    
  </div>    
  
  <div class="form-group">       
    <label for="body">Text: </label>        
    <InputTextArea Id="body" Class="form-control" @bind-Value="@Model.Text"></InputTextArea>        
    <ValidationMessage For="@(() => Model.Text)" />    
  </div>    
  <button type="submit">Ok</button> 

</EditForm> 

@code {    
	private string StatusMessage;    
	private string StatusClass;     

	private GuestbookEntry Model = new GuestbookEntry();     
	
	protected void HandleValidSubmit()    
	{        
		StatusClass = "alert-info";        
		StatusMessage = DateTime.Now + " Handle valid submit";    
	}     

	protected void HandleInvalidSubmit()    
	{        
		StatusClass = "alert-danger";        
		StatusMessage = DateTime.Now + " Handle invalid submit";    
	}
}


EditForm is a Blazor container for forms. Validator is added like any other Blazor component. The page above uses DataAnnotationValidator, but you can create custom one if you like.

Here is the screenshot demonstrating form when fields are empty and the Ok button is clicked.

Blazor guestbook form is invalid


This is the form with successful validation.

Blazor guestbook form is valid


I think most developers will be okay with this solution, and I can finish this writing. Or no?

Disable Button Until Form Is Valid

We can actually dig deeper and try something fancy. What if we want an Ok button to be disabled while the form is invalid? I found a blog post Disabling the Submit button in Blazor Validation by Peter Himschoot where he provides a solution through custom InputWatcher.

My solution is smaller. We can assign to EditForm either Model or EditContext but not both at the same time. When using EditContext, we have way more control over validation. This way, I solved the need for additional components.

I solved the button-disabled-status problem with a simple but not so straightforward trick. Instead of a boolean value for the disabled attribute, I went with string. The value is either “disabled” or null. Notice that an empty string leaves “disabled” attribute on button. I had to listen to the field change event just like Peter did.

@page "/"
@using  BlazorFormValidation.Models 

<h1>My guestbook</h1> 

<p>Leave me a message if you like my site</p> 

<EditForm EditContext="@EditContext">       
	<DataAnnotationsValidator />        
  
  	<div class="form-group">        
    	<label for="name">Name: </label>        
        <InputText Id="name" Class="form-control" @bind-Value="@Model.Name"></InputText>        
        <ValidationMessage For="@(() => Model.Name)" />    
    </div>    
    
    <div class="form-group">        
    	<label for="body">Text: </label>        
        <InputTextArea Id="body" Class="form-control" @bind-Value="@Model.Text"></InputTextArea>        
        <ValidationMessage For="@(() => Model.Text)" />    
    </div>    
    <button type="submit" disabled="@OkayDisabled">Ok</button> 

</EditForm> 
    
@code 
{    
	private EditContext EditContext;    
    private GuestbookEntry Model = new GuestbookEntry();     
          
    protected string OkayDisabled { get; set; } = "disabled";     
          
    protected override void OnInit()    
    {        
      	EditContext = new EditContext(Model);        
      	EditContext.OnFieldChanged += EditContext_OnFieldChanged;         
      
      	base.OnInit();    
    }     
          
    protected override void OnAfterRender()    
    {        
    	base.OnAfterRender();         
      
      	SetOkDisabledStatus();    
    }     
          
    private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)    
    {        
      	SetOkDisabledStatus();    
    }     
          
    private void SetOkDisabledStatus()    
    {        
      	if(EditContext.Validate())        
        {            
          	OkayDisabled = null;        
        }        
      	else        
        {            
          	OkayDisabled = "disabled";        
        }    
    }
 }


This is how guestbook opens when I run it. Validation messages are shown for fields, and the Ok button is disabled.

Blazor guestbook: button is disabled if form is invalid


With the EditContext class, we were able to take form under our control.

Inside EditContext Class

There’s more about EditContext. Take a look at the EditContext class definition.

public sealed class EditContext
{    
  public EditContext(object model);    
  public object Model { get; }     
  public event EventHandler<FieldChangedEventArgs> OnFieldChanged;    
  public event EventHandler<ValidationRequestedEventArgs> OnValidationRequested;    
  public event EventHandler<ValidationStateChangedEventArgs> OnValidationStateChanged;     
  
  public FieldIdentifier Field(string fieldName);    
  public IEnumerable<string> GetValidationMessages();    
  public IEnumerable<string> GetValidationMessages(FieldIdentifier fieldIdentifier);    
  public bool IsModified();    
  public bool IsModified(in FieldIdentifier fieldIdentifier);    
  public void MarkAsUnmodified(in FieldIdentifier fieldIdentifier);    
  public void MarkAsUnmodified();    
  public void NotifyFieldChanged(in FieldIdentifier fieldIdentifier);    
  public void NotifyValidationStateChanged();    
  public bool Validate();
}


It has events that are triggered for changes. We have methods to mark fields as unmodified; it’s easy to get field ID used by Blazor and notify EditContext of changes if we need to.

Check Validation Status When Field Changes

There’s one more minor thing to solve on our form. When form gets valid I want Ok button to be enabled at same moment and not when I leave the field. This functionality would be great for fields validated by regular expression, by example.

After some research and hacking I came out with ugly solution using KeyUp event and reflection (I’m sure Blazor guys don’t want you to do it at home). But here my solution is.

@page "/"
  @using BlazorFormValidation.Models 
  
  <h1>My guestbook</h1> 
  
  <p>Leave me a message if you like my site</p> 
  
    <EditForm EditContext="@EditContext">    
    	<DataAnnotationsValidator />     
    
    <div class="form-group">        
    	<label for="name">Name: </label>        
        <InputText Id="name" Class="form-control" @bind-Value="@Model.Name" onkeyup='@(e => KeyUp(e, "Name"))'>
   </InputText>        
   		<ValidationMessage For="@(() => Model.Name)" />    
    </div>    
    
    <div class="form-group">        
    	<label for="body">Text: </label>        
        <InputTextArea Id="body" Class="form-control" @bind-Value="@Model.Text" onkeyup='@(e => KeyUp(e, "Text"))'>
    </InputTextArea>        
    	<ValidationMessage For="@(() => Model.Text)" />    
    </div>    
    <button type="submit" disabled="@OkayDisabled">Ok</button> 
    
    </EditForm> 
    
    @code
    {    
    	private EditContext EditContext;    
        private GuestbookEntry Model = new GuestbookEntry();     
          
        protected string OkayDisabled { get; set; } = "disabled";     
          
        protected override void OnInit()    
        {        
          EditContext = new EditContext(Model);        
          EditContext.OnFieldChanged += EditContext_OnFieldChanged;         
          
          base.OnInit();    
        }     
          
        protected override void OnAfterRender()    
        {        
          base.OnAfterRender();         
          
          SetOkDisabledStatus();    
        }     
          
        private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)    
        {        
          SetOkDisabledStatus();    
        }     
          
        void KeyUp(UIKeyboardEventArgs e, string memberName)    
        {        
          var property = Model.GetType().GetProperty(memberName);        
          var value = property.GetValue(Model);        
          property.SetValue(Model, value + e.Key);         
          
          var id = EditContext.Field(memberName);         
          
          EditContext.NotifyFieldChanged(id);    
        }     
          
        private void SetOkDisabledStatus()    
        {        
          if (EditContext.Validate())        
          {            
            OkayDisabled = null;        
          }        
          else        
          {            
            OkayDisabled = "disabled";        
          }    
        }
     }


It’s a small thing, but users will love it. We just made our form even more responsive.

Using Other Validators

I found a FluentValidation support for Blazor by Chris Sainty. FluentValidation is a popular validation library that supports also advanced validation scenarios.

With FluentValidation we use validator classes like the one shown here.

public class GuestbookEntryValidator : AbstractValidator<GuestbookEntry>
{    
	public GuestbookEntryValidator()    
    {        
    	RuleFor(e => e.Name)                
        	.NotEmpty().WithMessage("Name is required")                
            .MaximumLength(10).WithMessage("10 characters maximum");         
        
        RuleFor(e => e.Text)                
        	.NotEmpty().WithMessage("Text is required");    
    }
}


Our form doesn’t change much. We just have to change the validator component.

<EditForm EditContext="@EditContext">    
  <FluentValidationValidator />     
  
  <div class="form-group">        
    <label for="name">Name: </label>        
    <InputText Id="name" Class="form-control" @bind-Value="@Model.Name"></InputText>        
    <ValidationMessage For="@(() => Model.Name)" />    
  </div>    
  
  <div class="form-group">        
    <label for="body">Text: </label>        
    <InputTextArea Id="body" Class="form-control" @bind-Value="@Model.Text"></InputTextArea>        
    <ValidationMessage For="@(() => Model.Text)" />    
  </div>    
  <button type="submit" disabled="@OkayDisabled">Ok</button> 

</EditForm>


Now, we can use the full power of FluentValidator on our forms. Check out FluentValidationValidator source code from Github repository chrissainty/FluentValidationWithRazorComponents.

Wrapping Up

There are two ways to go with validation on Blazor. We can use a Model property of EditForm and keep things simple for us. If we need more control over validation and UI then we can provide EditContext to EditForm. Those who want to go deep into internal functionality can see how Christ Sainty integrated FluentValidation to Blazor. Although there can be changes to form validation over the coming releases of Blazor, we can still start building our own advanced components to use with Blazor applications.

Form (document) Blazor

Published at DZone with permission of Gunnar Peipman. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Build a Dynamic Web Form Using Camunda BPMN and DMN
  • Automating a Web Form With Playwright MCP and MySQL MCP
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes
  • Dynamic Web Forms In React For Enterprise Platforms

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook