MudForm Validation with MudBlazor & Fluent Validation
tl;dr
You're going to have to manually call your FluentValidation
validator to ensure your view model is valid before you save any data and the validator must include the state of the entire view model, including any child and nested child view models.
In my case I want to keep the Save
button enabled at all times, instead of disabling it when the values the user enters are not valid. My personal preference is not to send the user hunting for the reason they can't save their work. It always pisses me off. Let them try, then tell them what they have to do to fix it.
At the same time, I want immediate feedback directly where they are looking as they enter their data so that they can correct it while their attention is in the context of that value. So, they don't have to wait to press save to go back and fix obvious problems, like an incomplete phone number. Greedy, I know.
I'm confused. Again.
The key is that MudBlazor
form validation only applies to the fields that have a validation parameter associated with them. It has no idea about an entire FluentValidation
validator you created. All the form fields may pass their own validation test but the overall state of your view model (all the stuff you're trying to get ready to send somewhere) may be invalid.
And on some controls, validation isn't supported. Especially if you make your own custom controls. To be clear, there's a way to do it. I hear people talk about it, but I can't figure it out.
A hybrid solution.
Since I'm tying this to my Save
button approach, it's important that this validator ensure the entire view model is valid, regardless of how I'm handling validation for fields, components and even nested child components.
You start by creating a FluentValidation
validator and then adding the extra ValidateValue
function as shown in the MudBlazor documentation.
To make this work, you pass a parameter called Model
and another called Validation
.
The important thing to note is that the Validation
parameter is a function that looks like this: "@(validator.ValidateValue)"
. Its only purpose is to supply the default function for a field that doesn't have its own validation on it. (See the docs mentioned above.) You can specify validation for an individual form field that isn't tied to FluentValidation
but I have only done that when I'm validating manually.
Then on a form field, you can specify the name of the property in the view model that applies to this field using the For
parameter. Mine looks like this:
What this does is tell the form that it has a field that it can validate, and to show it with failed validation emphasis (red) and the proper message when it fails and to clear those when it passes validation. I really like the way the authors handled it and try to use it as much as possible.
This handles the cases where I want the form to show failed validation immediately after the user leaves the field.
Let's try saving it.
In whatever save logic you have you'd probably have statements like these:
When form.Validate()
runs, any fields failing validation will show their error messages.
But this is only going to validate the fields on the form with the For
statement.
What it doesn't do is run the entire validator. If you have child components that have their own validators they won't run, form.IsValid
will return true and now we have a problem.
For
is not for everyone
It turns out that not all MudBlazor
controls support validation, like MudChipset
. Which means we can't use the built in support for our own controls, even if they are combinations of MudBlazor
controls.
These could be custom controls that use a MudForm
of their own, or custom controls that don't use MudForm
at all.
In those cases, we'll have to use some manual validation, use MudBlazor's
handy way of displaying error state, etc.
Now can we Save it?
We'll need to update our save logic to include manually calling our FluentValidation
validator.
In my case, I ended up writing my own ValidationSummary
that appears when they try to save and there are problems. I did that so I could update that summary as they made each correction. When all the corrections are complete, I clear the summary and pop up a little toast notification telling them everything is good. Now they can press Save
.