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

.NET 8 Blazor - Cannot submit the form because no form on the page currently has that name. #55808

Closed sbwalker closed 5 months ago

sbwalker commented 5 months ago

Is there an existing issue for this?

Describe the bug

When creating a static component which has a form element that is rendered based on conditional logic, the form will be displayed:

image

However when a user clicks a button to submit the form it will display a message at the top of the browser window "Cannot submit the form because no form on the page currently has that name." .

image

No exception is raised... it is simply a hard crash of the web UI. Refreshing the page in the browser will restore the UI (because it resets the state).

Expected Behavior

The form onsubmit handler should execute as expected, without throwing an error.

Steps To Reproduce

The following is a minimal repro:

@page "/"

<PageTitle>Form Error</PageTitle>

@if (string.IsNullOrEmpty(_message))
{
    <form method="post" @formname="Form1" @onsubmit="DisplayMessage" data-enhance>
        <AntiforgeryToken />
        <button type="submit" class="btn btn-primary">Submit Form1</button>
    </form>
}
else
{
    <div class="alert alert-info" role="alert">
        @_message
        <form method="post" @formname="Form2" @onsubmit="DismissMessage" data-enhance>
            <AntiforgeryToken />
            <button type="submit" class="btn btn-primary">Submit Form2</button>
        </form>
    </div>
}

@code {
    string _message = "";

    private void DisplayMessage()
    {
        _message = "Now Click The Button To Dismiss The Message";
    }

    private void DismissMessage()
    {
        _message = "";
    }
}

Exceptions (if any)

No exceptions are thrown - a message is displayed in the browser

.NET Version

8.0.4

Anything else?

Note that this does not appear to be an Enhanced Navigation issue, as it even occurs when the data-enhance attribute is removed from the form element.

javiercn commented 5 months ago

@sbwalker thanks for contacting us.

This is a developer error and by design. It's a requirement that if a form was rendered in SSR it needs to be rendered on to the page before we can dispatch the event. Otherwise, there is simply no way for us to associate the form name with the event handler nor to run any of the validations that the form might have.

sbwalker commented 5 months ago

@javiercn when you say "developer error" I assume you mean "Blazor limitation" as it is fairly common practice in web UX design to display a form based on a button click in order to capture some additional input.

The scenario where I encountered this behavior was a simple form where I wanted to capture some input from a user. I did not want the form to be displayed by default... I wanted them to click a button to reveal the form. And this component needed to be statically rendered because it is on a page in a public website where I do not want Blazor interactivity (ie. SignalR or WebAssembly).

Here is a minimal repro - however you can imagine that the real-world form may need to collect a lot more input fields than just an email address - which is why it is beneficial for the form to only be made visible when the user expresses intent.

image

Here is the code:

@page "/"

<PageTitle>Form Error</PageTitle>

<form method="post" @formname="Form1" @onsubmit="DisplayForm" data-enhance>
    <AntiforgeryToken />
    <button type="submit" class="btn btn-primary mb-3">Click Here To Provide Your Email</button>
</form>

@if (_display)
{
    <form method="post" @formname="MyForm" @onsubmit="SaveEmail" data-enhance>
        <AntiforgeryToken />
        <input name="email" class="form-control mb-3" placeholder="Enter Your Email" @bind="@_email" />
        <button type="submit" class="btn btn-success">Save Email</button>
    </form>
}

@code {
    private bool _display = false;
    private string _email = "";

    [SupplyParameterFromForm(FormName = "MyForm")]
    public string email { get => ""; set => _email = value; }

    private void DisplayForm()
    {
        _display = true;
    }

    private void SaveEmail()
    {
        // validate and save to database
        _display = false;
    }
}

And when clicking Save Email this crashes with the form name error:

image

This is really strange behavior from a developer perspective, as it there is nothing wrong with the way the form element is specified in my component. I spent quite a bit of time trying to trouble-shoot this problem as I assumed I was doing something incorrectly in my code... and I can only assume other developers will find this equally confusing.

So the question is... when using static rendering and needing to capture user input based on a visibility condition, what is the recommended solution for resolving this? Do you suggest using CSS/JavaScript to hide/show the form rather than using conditional logic in the component code?

dotnet-policy-service[bot] commented 5 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.

sandyhyd2021 commented 4 months ago

Extremely poor support for Blazor in .net 8. it will die soon. you guys cann't sustain against react and angular.

boreys commented 2 months ago

Blazor form is not working well, so I try to use MVC view, but this Blazor form logic keep interfering with MVC view form and keep throwing error like: Cannot submit the form 'imageForm' because no form on the page currently has that name.

I'm trying to avoid Blazor form by using MVC controller and views and Ajax; and I cannot disable this form behavior.

this is frustrating

pjc2007 commented 1 month ago

I get this without even having my form in an "if", it is there straight up. I've given the form an id everyway I can think of...

 <EditForm id="LoginForm" Model="@Model" OnValidateSubmit="Authenticate" @formname="LoginForm" FormName="LoginForm">

I cannot use @rendermode InteractiveServer as I then get no HttpContext to sign in against...

meisam-dehghan commented 1 month ago

Maybe one thing to do is to put the logic to render the form elements inside the form tag. This way, the form name would be rendered initially, yet the elements inside would only be displayed once the user clicks the button.

meisam-dehghan commented 1 month ago

Another way to deal with this issue is to have a form tag with just the formname and onsubmit on the page outside the condition that will render the main form with UI elements.Then within the main form that is rendered based on a specific condition,add an input with the name _handler and the value that correspond to name of form you specified for the form outside the condition

if (_showDeleteConfirmation)
{
 <form method="post" data-enhance>
  <input type="hidden" name="_handler" value="DeleteConfirmationForm" />
                ...
</form>
}
<form @formname="DeleteConfirmationForm" @onsubmit="@HandleDeleteFormSubmit"></form>