Making Blazor validation play nice with Bootstrap 4

There’s no doubt about it, blazor’s forms module and it’s validation features are fantastic.

You get all the benefits of using validation attributes on your models, along with a very fluid and real time UI model that works exactly the same in server and client modes.

There is however, one small problem with it all “Class Names

Take the following form:

If we look at it’s styles after failing validation in the web debugging tools we can see the following:

Blazor, like MVC and Webforms inserts the class names “invalid”, “valid” and as you’ll see later “modified”.

As well as that, they use “validation-message” for the message following the field.

Now this is all good if your then prepared to open your CSS editor and build your own styles to produce red/green/yellow etc styles as needed, however if your using Bootstrap to style your forms and pages which A) Comes as default in most of the .NET web templates, and B) as a huge amount of developers writing forms based apps do, then why create a whole set of new CSS just to provide styling for something you already have available.

This form:

Is a pure Bootstrap4 form, and when the form fails validation, this is what you’ll see:

If you look at the CSS names on the tags this time you’ll see 2 key differences:

  1. The CSS Names are almost the same except that the BS4 ones are prefixed with “is-
  2. The validation message is called “invalid-feedback

BS4 also has a “valid-feedback” message type too, and the library will actually hide/show the appropriate one as needed depending on the “is-valid” or “is-invalid” state of the preceding input field.

In the second example above, the form is in Razor pages, and Razor pages just like Blazor uses “valid” and “invalid” as CSS class names, I fixed the Razor version of it by inserting a small bit of JavaScript into the foot of the page using an HTML partial:

    let errorElements = Array.from(document.getElementsByClassName("input-validation-error"));
    errorElements.forEach(element => {

      let inputElement = $(element);
      let messageDiv = inputElement.next("div");

      if (messageDiv) {
        messageDiv.text(inputElement.data("val-required"));
      }

      inputElement.addClass("is-invalid");

    });


This works simply because the Razor page model is a full page load, so inserting that after the DOM has been constructed means that it will get executed automatically, and simply just find the class names you want to change and change them as appropriate.

Unfortunately, this does not work the same way in Blazor due to the fact that Blazor’s rendering model is designed to work the same way as a single page app without a page reload.

So then, how do we fix this for Blazor?

Well, there is an open ticket on GitHub static that we will get the ability to customize the class names in the future, probably around about .NET 5 when it gets released next year.

For now however, I did some nosing around in the source code, and came across this file:

https://github.com/aspnet/AspNetCore/blob/8d46b3a64ea784c95dddeb9d421c7cda6de993a2/src/Components/Web/src/Forms/EditContextFieldClassExtensions.cs

Which is where the actual CSS names are generated for all of the components in the “InputXXXXX” group.

My first thought was, ok then let’s see if we can override this, it’s only an extension, I’m sure I can replace it somehow.  After about 5 hours of trying however, I gave up and started looking at other ways.

I got reading Chris Sainty’s blog post on hooking up Fluent Validation for some ideas, but got no where with that one either.

Then I spotted something in the Blazor Docs on the “Components” page, that looked like it might help.

In the blazor doc is a small section that shows you how to override the “InputText” component to provide your own version, that instead of waiting until there’s a blur event to validate, it performs the validation on input:

More specifically I noticed the assignment of the “@CssClass” string to the class on the input element.

At first I just tried prefixing the entire string with “is-” but quickly found out, that all that did was prefix the entire string.

Since this was a razor component, I realized I could also add a “code” section to it, so I did, that code segment quickly became the following:

 

@code {

  private string fixClassNames(string inputClassNames)
  {
    //NOTE: Notice the space in front of the class name, this is to ensure we get
    // the suffix to our existing form-control class set from the mark up and NOT
    // half of an invalid tag.  We could use a reg-ex but that might be a bit
    // too slow for the UI renedering to stay smooth.

    // The invalid string shall always be fixed up, as we can never get it until the
    // element has chacked at least once by an attempted submit.
    string result = inputClassNames.Replace(" invalid", " is-invalid");

    // The valid tag is on by default, and to keep consistancy with BS4 we only want
    // it to appear either when our field is modified, or we've tried a submit
    if (inputClassNames.Contains("modified"))
    {
      result = result.Replace(" valid", " is-valid");
    }

    return result;
  }

}

Now this is a bit “Hacky” but it does work, and it works surprisingly well.

By default Blazor applies the “valid” class name to the form elements even before Validation, and we don’t really want to put the green tick etc on the form in the first place, so we only modify the “valid” CSS class name IF the class list also contains “modified”.

This stops the form appearing initially as validated, and only applies the green valid state if a field is valid after it’s been validated at least once.

Note also that we do a check for “invalid” first as that a) needs to work what ever the state and b) if we change it second the the sub string “valid” in it’s entire word would get changed to “is-valid” and screw up the entire class name.

That leaves just the “validation-message” component, and since that does not use the same component base as the input elements, quite frankly it was easier just to make a copy of the entire component class from here:

https://github.com/aspnet/AspNetCore/blob/8c02467b4a218df3b1b0a69bceb50f5b64f482b1/src/Components/Web/src/Forms/ValidationMessage.cs

Once you have a copy change the namespace to your pages/shared folder, then rename the class at line 14 from “ValidationMessage<TValue>” to something like “BS4ValidationMessage<TValue>“.

Scroll down to line 77 builder.AddAttribute(2, "class", "validation-message"); and change it to builder.AddAttribute(2, "class", "invalid-feedback");

Save the changes in your pages/shared folder, and at the same time create over ridden templates with the CSS class fix code in in the same folder with appropriate names for the input types you want to fix up.

Here’s my full version of the “BS4InputText.razor” component:

 

@inherits InputText



@code {

  private string fixClassNames(string inputClassNames)
  {
    //NOTE: Notice the space in front of the class name, this is to ensure we get
    // the suffix to our existing form-control class set from the mark up and NOT
    // half of an invalid tag.  We could use a reg-ex but that might be a bit
    // too slow for the UI renedering to stay smooth.

    // The invalid string shall always be fixed up, as we can never get it until the
    // element has chacked at least once by an attempted submit.
    string result = inputClassNames.Replace(" invalid", " is-invalid");

    // The valid tag is on by default, and to keep consistancy with BS4 we only want
    // it to appear either when our field is modified, or we've tried a submit
    if (inputClassNames.Contains("modified"))
    {
      result = result.Replace(" valid", " is-valid");
    }

    return result;
  }

}

This can then be used in place of a normal “InputText” component with exactly the same parameters, just by changing the tag to “BS4InputText“.

You can find the code for my components at:

https://github.com/shawty/BS4Inputs

One thing to note is the number input.  That actually has to take a generic type to get it working, and in my case I’ve only done an INT.  If you need decimal, double etc you’ll need to copy that file a bunch of times, rename appropriately and change the generic type to the number type you want to represent.

If anyone can come up with a way to extend it using the underlying generic type I’d love to see the solution.

Once you’ve copied the files into your Pages/Shared folder and adjusted the namespaces appropriately, you can use these components in the same way as the originals:

If you mark up your form elements in div’s with “form-group” classes and using “form-control” on the input elements, you’ll get exactly the same experience as using Bootstrap4 in a regular web page.

It’s nothing flash, but it works, at least until someone comes up with a better method 🙂

Have fun

Shawty

 

Rediscovering Postgres and EF core

Its ok folks, you can relax, yes I’m not ill, yes I have gotten around to writing another blog post, yes I know…. I don’t write enough anymore and I should 🙂

With that out the way, why am I suddenly getting all excited about Postgres and EF again (specifically EF core)

Continue reading “Rediscovering Postgres and EF core”

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.
Continue reading “Pure HTML Validation in Blazor”

Bootstrap 4 Succinctly Released

The 8th book Iv’e written to date for Syncfusion’s ever popular Succinctly eBook series, and the third one one Bootstrap.

As Bootstrap continually gets better and more feature rich, then there is a need to keep up to date with the latest offerings it provides.

In this book, I take you on a just over 100 page tour of what’s new, and what it can now do (Hint: Flexbox rules!!!) and show you how to produce some interesting layouts.

Best part about it all is it’s free!!!

You can grab a copy here: Succinctly eBooks

 

Typescript for the C# developer

Over the past couple of years, my most popular talk that Iv’e taken around user groups has been the one where I describe what Typescript is, and how it relates to the backend C# developer.

Iv’e found that many back-end devs who would like to jump into client side development, are often put off from doing so simply beacuse of the percieved mess that the JavaScript eco system is in at present, and let’s be fair it’s not a compleatly unfounded reason either, beacuse JavaScript is bleeding at the edges in a great many places.
Continue reading “Typescript for the C# developer”

Build Automation for Dotnet Core Apps

In a previous blog post I documented how I built a “Build Server” to deploy .NET 4.6+ apps on windows 2012 server.

While this worked, and was a reasonably good way to do it, It wasn’t without it’s problems. During it’s use for example I frequently had timing problems, where just one little change to some JS code would cause NPM to overrun a time out by half a second, or where an SSH connection timed out just slightly before the build server completed it’s login, and on top of all that, it regularly used to take about 15 minutes to build and deploy the project it was being used for. Continue reading “Build Automation for Dotnet Core Apps”