-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Background and Motivation
I am starting to learn Blazor and I faced small challenge, that frankly should be easy - enabling "submit" button if the form is valid. In Angular it's very simple:
<button [disabled]="!form.valid">Submit</button>
But in Blazor? Suggested solution is to listen to field change and call Validate()
on that. But my validator (eg. <DataAnnotationsValidator />
) is already doing that! So why should I do validation twice to get this functionality? And in documentation it's stated that this will cause generation of validation messages for all properties. First suggestion: "Don't use a ValidationSummary component on the form."
W...what? And second is some workaround. This is bad! For someone coming from Angular, this is terrible.
How can we make it better? Well, we could do something like this:
public bool IsSubmittable => !_editContext.GetValidationMessages().Any() && _editContext.IsModified();
But! There's a catch. _editContext.IsModified()
returns true if any property on the model is modified.
And so there's no way for me to check if all fields were modified. Well I can! Using reflection but that's ugly! Especially when FIeldState
is an internal class. And everything is sealed so there's no way for me to extend it without essentially rebuilding entire EditForm
, EditContext
and InputText
aswell as InputBase
. Which I don't want to. So here's my proposition:
Proposed API
namespace Microsoft.AspNetCore.Components.Forms;
public sealed class EditContext
{
+ public bool AllModified()
+ {
+ foreach (var state in _fieldStates)
+ {
+ if (!state.Value.IsModified)
+ {
+ return false;;
+ }
+ }
+ return true;
+ }
}
But that won't work without one more modification I guess. I haven't analyzed it thoroughly but I don't see that InputBase
"tells" EditContext
that it exist when it's initialized. So each input control would need to be registered in EditContext
but since each control inherits from InputBase
it will require only modification on InputBase
. But I am not sure about that, maybe it already works this way.
Usage Examples
public bool IsSubmittable => ! _editContext.GetValidationMessages().Any() && _editContext.AllModified();
<button class="btn btn-primary btn-large" disabled="@(!IsSubmittable)">Submit</button>
Alternative Designs
Alternative design would be to add some way to iterate over register fields that would give more flexibility to the developer on how to process that.
Even more alternative design would be to add reactive forms just like they exist in Angular but that would require dependency on reactivex. Would be very cool nevertheless.
Risks
No risks, it's a new method that only reads from internal state of EditContext
. There could be small risk if modification to InputBase
is needed, because that would change slightly it's behaviour.
In summary
I think this improvement would be very nice, especially for people new to Blazor. And I wish Blazor could one day overrule all those awful JavaScript frameworks ^_^