dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.37k stars 9.99k forks source link

Custom validation class in blazor is not working as expected. #30459

Closed TanvirArjel closed 3 years ago

TanvirArjel commented 3 years ago

First of all, Custom validation class attributes documentation is quite ambiguous and lack of clear instructions. It is not even stated that where to put the following code:

var editContext = new EditContext(model);
editContext.SetFieldCssClassProvider(new MyFieldClassProvider());

I have assumed that the above code has to be put inside at the beginning of HandleValidSubmit method. If I do so then it does not work on Model validation by validation attributes (data annotations) as model validation is done even before hitting the HandleValidSubmit method.

Secondly, If I am to do so then it means there is no global option to configure this. Rather I have to call the above code in every form submit which is even not working as expected?

Please confirm whether I have configured the Custom validation class attributes (as described above) correctly or it is a bug.

mkArtakMSFT commented 3 years ago

Thanks for contacting us and bringing up this concern.

The code you're referring to should be placed in the component initializer. Also, you have to wire up the EditContext instance that you've created with the form by passing it as a parameter.

@guardrex do you want to address the first part of it in docs somehow?

ghost commented 3 years ago

Thanks for contacting us. We're moving this issue to the Next sprint planning milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

TanvirArjel commented 3 years ago

@mkArtakMSFT There is another major issue. If I do as follows:

<EditForm EditContext="@editContext" OnSubmit="@HandleSubmit">

    <button type="submit">Submit</button>
</EditForm>

@code {
    private SetUserPasswordModel SetUserPasswordModel = new SetUserPasswordModel();
    private EditContext editContext;

    protected override void OnInitialized()
    {
        editContext = new EditContext(SetUserPasswordModel);
        editContext.SetFieldCssClassProvider(new BootstrapValidationClassProvider());
    }

    private async Task HandleSubmit()
    {
      .....
    }
}

Where BootstrapValidationClassProvider is as follows:

   public class BootstrapValidationClassProvider : FieldCssClassProvider
    {
        public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
        {
            bool isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

            return isValid ? "is-valid" : "is-invalid"; // Bootstrap validation class
        }
    }

Then the form initially renders as follows:

InkedCapture_LI

Although the form inputs have not been touched yet. This is because FieldCssClassProvider is setting is-valid class even before the form is touched which should not be. So currently setting a custom validation class of any CSS library would not work with this. I hope you understood. Validation state class should only be set if the input field is touched.

To prevent this if I do as follows:

public class BootstrapValidationClassProvider : FieldCssClassProvider
{
    public override string GetFieldCssClass(EditContext editContext, in FieldIdentifier fieldIdentifier)
    {
        if (editContext == null)
        {
            throw new ArgumentNullException(nameof(editContext));
        }

        if (!editContext.IsModified())
        {
            return string.Empty;
        }

        bool isValid = !editContext.GetValidationMessages(fieldIdentifier).Any();

        return isValid ? "is-valid" : "is-invalid";
    }
}

Then "is-valid" and "is-invalid" classes are not applied on the form submit because on form submit without touching the input fields editContext.IsModified() returns false. If editContext.IsModified() would have returned true on form submit and marked all fields as modified then It would have worked as expected.

I have also found that there is no way to mark editContext as modified on the form submit. Angular and React have this option to mark the form and its inputs as modified on form submit manually.

guardrex commented 3 years ago

@mkArtakMSFT ... The PR is up at https://github.com/dotnet/AspNetCore.Docs/pull/21634.

I put a piece in there at the end that mentions conditionally checking a subset of fields.

I'll touch it again later when I reach the topic on my UE pass. For example, a fully working cut-'n-paste example might be best, and I might work that up later. Let's see if what's on the PR is good enough for now.

mkArtakMSFT commented 3 years ago

@TanvirArjel for the there is another major issue part, can you please file a separate issue so we keep this issue clean ?Thanks!

TanvirArjel commented 3 years ago

@mkArtakMSFT Surely! I shall do. We ❤️ Blazor a lot. It's a mind-blowing framework. We want to see it as fully stable as Angular. Thanks to all you guys behind this framework.

TanvirArjel commented 3 years ago

This is issue being closed in favour of https://github.com/dotnet/aspnetcore/issues/30496