'How to place submit button for a Blazor EditForm outside of the component

The Blazor documentation's Form Validation example has a submit button component within the EditForm component:

    <EditForm Model="@starship" > OnValidSubmit="@HandleValidSubmit">
        <DataAnnotationsValidator />
        <ValidationSummary />
    
        <p>
            <label for="identifier">Identifier: </label>
            <InputText id="identifier" bind Value="@starship.Identifier" />
        </p>
    
        Snip....

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

        Snip...

    </EditForm>

Is there anyway to place that submit button outside of the EditForm tags and still have it 'natively' trigger the submit for that EditForm component without resorting to using JavaScript?

i.e. for the code to look something like this:

    <!-- Want this button to submit the form in the EditForm tags-->
    <button type="submit">Submit</button>

    Snip...

    <EditForm Model="@starship" OnValidSubmit="@HandleValidSubmit">
        <DataAnnotationsValidator />
        <ValidationSummary />
    
        <p>
            <label for="identifier">Identifier: </label>
            <InputText id="identifier" bind-Value="@starship.Identifier" />
        </p>
    </EditForm>


Solution 1:[1]

It's very simple:

  • Add an id attribute to the EditForm
  • Put the submit button outside the EditForm, and assign to its form attribute the id of the EditForm.

Here's a working code sample:

    @using System.ComponentModel.DataAnnotations;    

    <EditForm id="@MyID" Model="Model" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />

    <div class="form-group">
        <label for="name">Name: </label>
        <InputText Id="name" Class="form-control" @bind-Value="@Model.Name"> 
        </InputText>
        <ValidationMessage For="@(() => Model.Name)" />

    </div>
    <div class="form-group">
        <label for="body">Text: </label>
        <InputTextArea Id="body" Class="form-control" @bind-Value="@Model.Text"> 
        </InputTextArea>
        <ValidationMessage For="@(() => Model.Text)" />
    </div>
    </EditForm>

    <p>
        <button type="submit" form="@MyID" class="btn btn-primary">Save</button>
        <button type="button" class="btn btn-light" 
                               @onclick="@Cancel">Cancel</button>
    </p>
    @code
    {
        private string MyID = "myid";

        private Comment Model = new Comment();

        public async Task HandleValidSubmit()
        {
            //  await Task.Delay(3000);

            await Task.Run(() =>
            {
                Console.WriteLine("Saving...");
                Console.WriteLine(Model.Name);
                Console.WriteLine(Model.Text);
            });

        }

        private void Cancel()
        {
            Console.WriteLine("Cancelling...");
            Console.WriteLine(Model.Name);
            Console.WriteLine(Model.Text);
        }

       public class Comment
       {
           [Required]
           [MaxLength(10)]
           public string Name { get; set; }

           [Required]
           public string Text { get; set; }

       }

    }

Hope this helps...

Solution 2:[2]

The accepted answer has helped me, but I'd like to point out that this variable in the code section is unnecessary:

private string MyID = "myid";

You can simplify this to:

<button type="submit" form="MyID" class="btn btn-primary">Save</button>

Snip...

<EditForm id="MyID" Model="Model" OnValidSubmit="HandleValidSubmit">

There was no need for the @MyID razor syntax variable to accomplish this.

Solution 3:[3]

For custom error message

[MaxLength(100, ErrorMessage = "Title is too long.")]
public string title { get; set; }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 tomRedox
Solution 2 Dharman
Solution 3 Mirko MyRent