Skip to content

[Blazor] EditContext: add a way to check if all registered fields were modifiedΒ #63463

@ScuroGuardiano

Description

@ScuroGuardiano

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 ^_^

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-suggestionEarly API idea and discussion, it is NOT ready for implementationarea-blazorIncludes: Blazor, Razor Components

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions