Pure HTML Validation in Blazor


There’s been a lot of talk about Validation in the Blazor gitter chat recently.

The Blazor dev team have added some validation routines in that closley mimic the way validation works in ASP.NET MVC and many folks have been playing with them to see what they can do with them.

Chris Sainty has even produced a blog post [https://chrissainty.com/using-fluentvalidation-for-forms-validation-in-razor-components/] showing how to wire in the “Fluent Validation” libraries to make form validation even more awesome.

All of this got me thinking.

In the last book I wrote for Syncfusion covering Bootstrap 4 [https://www.syncfusion.com/ebooks/twitterbootstrap4-succinctly] I covered using the CSS classes provided by BS4 for showing validation states, most of this validation is used completely client side and is actually just an extension on the now quite mature HTML5 Validation API Which Iv’e written about previously in this blog.

I got my copy of the PDF out and started to read the chapter on forms, and I wondered just how easy it would be to get the example I provide in the book, working in Blazor, this post is the result 🙂

The first thing I needed to do was to create a Blazor App, the code here won’t work with “Razor Components” or “Blazor Server Side”, so you’ll need to create either a “Blazor Client” or “Blazor Hosted” application.

I’m not going to go through the whole process here as it’ll be a wall of code, just enter:

dotnet new blazor
or
dotnet new blazorhosted

at the command line of your chosen OS (I was using Windows) in a folder where you would like to create your project.

The first thing you need is a form, I used a simple log in form for this example.

Create a page in the Pages Folder of your project, let’s call it “signin.cshtml”

The code in this page should look something like the following (Apologies for this being an image, but the word press editor just couldn’t handle this piece of code as anything else, you can click on it to make it bigger):

The important parts of this are the attributes on the form tag, and the classes used by bootstrap to format the colours of the text.

You’ll notice that the class on the form is set to needs-validation by default and you’ll notice that the form tag itself has a novalidate attribute on it.

They are there so that by default when the page is drawn, everything looks not validated, and so that the browser doesn’t try to apply any automatic validation to the form.

The input elements in this case have required attributes on them, so that when the time comes they will be validated against being empty.

Things like the correct input type “email”, “url”, “phone” etc and using “pattern” to check against reg-ex patterns will all cause different validation checks, checks that are handled entirely by the browser on your behalf.

There’s a very comprehensive guide on the Mozilla Developer Network to all the different ways you can mark up  your elements for validation available at https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Form_validation

If you look at the form element, you’ll see an attribute called ref, this is a Razor/Blazor attribute that allows you to get a reference to that HTML element, and then pass that reference into JavaScript in order to perform JavaScript operations on it.

We also define a variable in our C# code, to allow us to use the form reference so we can pass it into our “Blazor Utilities Library”

Blazor Utilities?

As part of the project, I’ve created a small JavaScript interop library, I added this to my solution by running

dotnet new blazorlib -o blazorutils

in the solution folder where my blazor application is.

The library contains a few usefull C# function wrappers, that allow me to call some javascript functions, to do a couple of tasks that I’m unable to do using plain old C#

The JavaScript file in the content folder simply just contains the following:

window.blazorUtilsFunctions = {

  setFocus: function (elementId) {
    let element = document.getElementById(elementId);
    if (undefined === element) return null;
    if (null === element) return null;
    element.focus();
    return null;
  },

  message: function (message) {
    alert(message);
  },

  isFormValid: function (formRef) {
    return formRef.checkValidity();
  }

};

UtilsInterop.cs is the C# interface to our JavaScript functions, and has the following code in it:

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System.Threading.Tasks;

namespace IntranetV6.BlazorUtils
{
  public class UtilsInterop
  {
    private IJSRuntime _jsRuntime;

    public UtilsInterop(IJSRuntime jsRuntime)
    {
      _jsRuntime = jsRuntime;
    }

    public Task<object> SetFocus(string elementId)
    {
      return _jsRuntime.InvokeAsync<object>(
          "blazorUtilsFunctions.setFocus",
          elementId);
    }

    public Task<object> Message(string message)
    {
      return _jsRuntime.InvokeAsync<object>(
          "blazorUtilsFunctions.message",
          message);
    }

    public async Task<bool> IsFormValidationValid(ElementRef formRef)
    {
      return await _jsRuntime.InvokeAsync<bool>(
          "blazorUtilsFunctions.isFormValid",
          formRef);
    }

  }
}

and finally BlazorUtils.cs is just a static class allowing us to add our library in the startup.cs of our application

using Microsoft.Extensions.DependencyInjection;

namespace IntranetV6.BlazorUtils
{
  public static class BlazorUtils
  {
    public static IServiceCollection AddBlazorUtils(this IServiceCollection services)
    {
      return services.AddSingleton<UtilsInterop>();
    }

  }
}

The setFocus routine is used to do exactly as it says, set focus on an input field, message is a simple alert box and isFormValid returns us a true or a false telling us if the validation on our form has failed or not, simply by asking the HTML5 validation API to check the rules defined on it for us.

You could put the JS routine directly into your main application if you wish, Chris has some advice on his blog about that subject as well as many others too 🙂

For me I wanted the lib to be reusable, so I can just use the DLL when I need my utilities.

Back to the form…

Going back to our form page, you’ll see the class in the form is actually driven using a bool variable in the pages function block. You don’t actually have to call the Validation API for the validation styles to work, if you change the boolean formValidated to true, Blazor will automatically change the class from needs-validation to was-validated and apply the correct colours, icons and even unhide any element with an invalid-feedback class on for you automatically.

The reason we call the function in our blazor utils library is simply to tell us if we should allow the form processing to continue or not, as can be seen with the if check followed by a return in the click handler on the forms login button.

The invalid-feedback class also has an opposite of valid-feedback which like it’s invalid counterpart will automatically un-hide when the form is in a valid state.

The various parts of the forms are grouped using block elements in a form-group class, this is important because it enables BS4 to know which parts relate to which valid/invalid parts of the form, an element marked to display when valid will only appear when the form group that it’s part of becomes valid, so like anything in bootstrap order of tags and classes is important.

All the heavy lifting of deciding what to show and how is done for you by BootStrap 4, just through changing one single class, and a simple check allows us to decide if the form should continue processing or not, if you have a design flow where your designers are insisting on having total control of the layout of your page forms, then this may be a better approach than using a pure code driven approach as others have, and it turned out to be a whole lot easier than I thought it would be to implement.

Shawty

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s