Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EditForm - How can I prevent submit on pressing enter key

Tags:

blazor

I've found this article but I'm having a hard time to understand how can I prevent submit on "enter" key independently by any <input>

<EditForm Model="exampleModel" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="exampleModel.Name" />
    <InputText id="name2" @bind-Value="exampleModel.Name2" />

    <button type="submit">Submit</button>
</EditForm>
@code {
    private ExampleModel exampleModel = new ExampleModel();

    private void HandleValidSubmit()
    {
        Console.WriteLine("OnValidSubmit");
    }

    public class ExampleModel
    {
         [Required]
         [StringLength(10, ErrorMessage = "Name is too long.")]
         public string Name { get; set; }
         public string Name2 {get; set;}
    }
}

Use Case

Enter key On HTML forms if you are filling out a text box and press the enter key it will submit the form, even if you haven't finished filling in the rest of the information. There are many websites which use this feature such as Google search box will submit when you press the enter key. This works because you only have one text box to fill out, but if there are more than one field to fill in you don't want the form to submit on the enter key.

like image 380
Leonardo Lurci Avatar asked May 27 '20 23:05

Leonardo Lurci


4 Answers

Leonardo Lurci, here's a complete solution implemented purely in C#, no JSInterop. As it turned out, Microsoft has already provided this feature, but they did not provide enough samples to demonstrate how to use it.

As it turned out, I cannot use the pair @onkeypress="@KeyHandler" and @onkeypress:preventDefault with the Forms components such as InputText, but applying these directives to Html tags is viable and works perfectly well. See for instance how I apply these directives to the "submit" button.

Consequently, I subclass the base class InputBase, this is the class from which the InputText components derive, overrides the default view rendering by adding an input element to which I can add the directives of the new feature.

TextBox.razor (this comes instead of InputText)


    @inherits InputBase<string>

    <input type="text" value="@CurrentValueAsString" id="Id" class="@CssClass" 
       @onkeydown="KeyDownHandler" @onkeypress="KeyPressHandler" 
                                                   @onkeypress:preventDefault/>

     @code{

    protected override bool TryParseValueFromString(string value, out string 
                                      result, out string validationErrorMessage)
    {
        result = value;
        validationErrorMessage = null;
        return true;
    }

    void KeyDownHandler(KeyboardEventArgs args)
    {
        if (args.Key == "Backspace" && CurrentValueAsString.Length >=1)
        {
            CurrentValueAsString = CurrentValueAsString.Substring(0, 
                                       CurrentValueAsString.Length - 1);
        }
    }

     void KeyPressHandler(KeyboardEventArgs args)
     {

        if (args.Key == "Enter")
        {
            return;
        }
        var key = (string)args.Key;
        CurrentValueAsString += key;
     }
    }

Usage


    <p>Leave me a comment</p>

    <EditForm Model="Model" OnValidSubmit="HandleValidSubmit" >
    <DataAnnotationsValidator />

     <div class="form-group">
        <label for="name">Name: </label>
        <TextBox Id="name" Class="form-control" @bind-Value="@Model.Name" >
        </TextBox>
        <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>
     <p>
        <button type="submit" @onkeypress="KeyHandler" @onkeypress:preventDefault>
            Submit
        </button>
     </p>
    </EditForm>


    @code
    {
        private Comment Model = new Comment();

        private void HandleValidSubmit()
        {
             Console.WriteLine("Submit...");
        }


        void KeyHandler(KeyboardEventArgs args)
        {
            if (args.Key == "Enter")
            {
               return;
             }
        }

        public class Comment
        {
            public string Name { get; set; } = "Jeff";
            public string Text { get; set; } = "I'm Jeff. I'm from Canada";
        }

    }

Please, don't hesitate to ask any questions

Hope this helps...

like image 175
enet Avatar answered Sep 24 '22 11:09

enet


As Enet suggested in the comments, there isn't a full Blazor (Csharp) solution for this use-case. You have to interact with JavaScript.

Currently, I solved with this workaround:

blazor-side

@inject IJSRuntime JS
<EditForm id="askQuestionForm" Model="exampleModel" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <InputText id="name" @bind-Value="exampleModel.Name" />
    <InputText id="name2" @bind-Value="exampleModel.Name2" />

    <button type="submit">Submit</button>
</EditForm>
@code {
    private ExampleModel exampleModel = new ExampleModel();

    private void HandleValidSubmit()
    {
        Console.WriteLine("OnValidSubmit");
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender) 
        {
            JS.InvokeVoidAsync("PreventEnterKey", "askQuestionForm");
        }
    }

    public class ExampleModel
    {
         [Required]
         [StringLength(10, ErrorMessage = "Name is too long.")]
         public string Name { get; set; }
         public string Name2 {get; set;}
    }
}

interop.js

function PreventEnterKey(id) {
    $(`#${id}`).keydown(function (event) {
        if (event.keyCode == 13) {
            event.preventDefault();
            return false;
        }
    });
}

I hope Microsoft will develop this feature in the future.

Thanks to Enet.

like image 23
Leonardo Lurci Avatar answered Sep 22 '22 11:09

Leonardo Lurci


Add event handlers to your input and submit elements like this:

<InputText id="name" @bind-Value="exampleModel.Name" @onkeydown="PreventSubmit"/>
<button type="submit" @onclick="ShouldISubmit">Submit</button>

Add this to your @code block:


public bool shouldsubmit { get; set; }

public bool entersubmit { get; set; }

public void PreventSubmit(KeyboardEventArgs ev)
{
    if (ev.Key == "Enter")
        entersubmit = true;
}

public void ShouldISubmit()
{
    if (entersubmit)
        shouldsubmit = false;
    else
        shouldsubmit = true;
    entersubmit = false;
}

Change your submit function to this


private void HandleValidSubmit()
{
    if (shouldsubmit) {
        Console.WriteLine("OnValidSubmit");
    }
}
like image 33
Prazlin Avatar answered Sep 23 '22 11:09

Prazlin


I found a simple solution that I think is the easiest option. Create a custom component that will be your submit button:

<button type="button" @onclick="OnClick" @attributes="UnmatchedAttributes">@Text</button>


@code {

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

    [Parameter]
    public Func<Task> OnValidSubmitAsync { get; set; }

    [Parameter]
    public Action OnValidSubmit { get; set; }

    [CascadingParameter]
    public EditContext EditContext { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> UnmatchedAttributes { get; set; }

    private async Task OnClick() {
        if (EditContext != null) {
            if (EditContext.Validate()) {
                if (OnValidSubmit != null) {
                    OnValidSubmit();
                } else {
                    if (OnValidSubmitAsync != null) {
                        await OnValidSubmitAsync();
                    }
                }
            }
        }
    }

}

This component acts as a submit button, but since its type is not submit, an enter won't trigger it. It accepts a cascading parameter of type EditContext which allows it to validate the form. It also accepts a delegate which will be triggered when it is clicked and the form state is valid.

Usage example:

<EditForm Model="model">
    <input type="text" @bind="model.Value" />
    @* Add the custom submit component*@
    <EditFormSubmit Text="Submit" OnValidSubmit="Submit" class="btn btn-primary"></EditFormSubmit> 
</EditForm>
like image 41
Michael Avatar answered Sep 23 '22 11:09

Michael