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

Call JS checkValidity() from Blazor EditForm - Get ElementReference for EditForm #52902

Closed Ogglas closed 10 months ago

Ogglas commented 10 months ago

Is there an existing issue for this?

Is your feature request related to a problem? Please describe the problem.

I'm trying to use HTMLSelectElement: checkValidity() for a Blazor EditForm

https://developer.mozilla.org/en-US/docs/Web/API/HTMLSelectElement/checkValidity

The reason for doing this is that a Required field is set based on non top-level properties and user input and therefore editContext.Validate(); does not work. I could perhaps use the experimental ObjectGraphDataAnnotationsValidator but since the form knows if it is valid or not this is good enough for me.

Describe the solution you'd like

In a normal html form I can validate it like this:

@inject IJSRuntime JSRuntime

<form method="post" @ref="_htmlForm" @onsubmit="Submit">
    <InputText @bind-Value="name" />
    <button type="submit">Submit</button>
</form>

@code
{
    private string name = "";

    private ElementReference _htmlForm;

    private async Task Submit()
    {
        bool isFormValid = await JSRuntime.InvokeAsync<bool>("isFormValid", _htmlForm);
        if (isFormValid == false)
        {
            return;
        }
    }
}

Index.cshtml:

<script>
    function isFormValid(formRef) {
        return formRef.checkValidity();
    }
</script>

However using a EditForm causes the following exception if I try to assign ref to a ElementReference:

CS0029 Cannot implicitly convert type 'Microsoft.AspNetCore.Components.Forms.EditForm' to 'Microsoft.AspNetCore.Components.ElementReference'

If I use EditForm like this:

@inject IJSRuntime JSRuntime

<EditForm @ref="_editForm" Model="name" OnValidSubmit="Submit" Context="editForm">
    <InputText @bind-Value="name" />
    <button type="submit">Submit</button>
</EditForm>

@code
{
    private string name = "";

    private EditForm _editForm;

    private async Task Submit()
    {
        bool isFormValid = await JSRuntime.InvokeAsync<bool>("isFormValid", _editForm);
        if (isFormValid == false)
        {
            return;
        }
    }
}

I get this exception:

blazor.webassembly.js?v=rcIWTVNnYus6VWf2Z2U1g_JzlC07Ym02cFjHtI59Xsc:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: Serialization and deserialization of 'Microsoft.AspNetCore.Components.RenderFragment1[[Microsoft.AspNetCore.Components.Forms.EditContext, Microsoft.AspNetCore.Components.Forms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]]' instances is not supported. The unsupported member type is located on type 'Microsoft.AspNetCore.Components.RenderFragment1[Microsoft.AspNetCore.Components.Forms.EditContext]'.

I could refactor JS to get HTML Id of the component but I think it should be possible to get ElementReference for a EditForm?

Additional context

No response

javiercn commented 10 months ago

@Ogglas thanks for contacting us.

EditForm is a component, not an HTML element. We don't expose the underlying HTML form element anywhere, however, you can give it a name by passing the name attribute and then change your JS code to do document.forms['myForm'].checkValidity()

It's not clear to me what you are trying to accomplish, but I would definitely go the way the ObjectGraphDataAnnotationsValidator than trying to use the checkValidity API. That won't work with any Blazor/C# validation logic, it will only work with HTML5 built-in validation logic.

ghost commented 10 months ago

This issue has been resolved and has not had any activity for 1 day. It will be closed for housekeeping purposes.

See our Issue Management Policies for more information.

Ogglas commented 10 months ago

@javiercn Thanks for your response! Solved it with HTML id attribute for now and will check out ObjectGraphDataAnnotationsValidator later.