编辑表单 - 如何防止按回车键提交



我找到了这篇文章,但我很难理解如何防止任何<input>独立地提交"enter"键

<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;}
}
}

用例

输入键 在HTML表单上,如果您正在填写文本框并按回车键,即使您尚未完成其余信息的填写,它也将提交表单。有许多网站使用此功能,例如当您按回车键时,Google搜索框将提交。这有效,因为您只有一个文本框要填写,但如果有多个字段要填写,您不希望在 Enter 键上提交表单。

Leonardo Lurci,这是一个纯粹用C#实现的完整解决方案,没有JSInterop。事实证明,Microsoft已经提供了此功能,但他们没有提供足够的示例来演示如何使用它。

事实证明,我不能将@onkeypress="@KeyHandler"@onkeypress:preventDefault对与 InputText 等表单组件一起使用,但将这些指令应用于 Html 标签是可行的,并且运行良好。例如,请参阅如何将这些指令应用于"提交"按钮。

因此,我对基类 InputBase 进行子类化,这是 InputText 组件派生的类,通过添加一个输入元素来覆盖默认视图呈现,我可以在其中添加新功能的指令。

TextBox.razor(代替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;
}
}

用法


<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";
}
}

请不要犹豫,提出任何问题

希望这有帮助...

将事件处理程序添加到输入并提交如下所示的元素:

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

将此添加到您的@code块:


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;
}

将您的提交功能更改为此


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

正如Enet在评论中建议的那样,对于这个用例,没有完整的Blazor(Csharp)解决方案。你必须与 JavaScript 交互。

目前,我用这个解决方法解决了:

布莱泽侧

@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;}
}
}

互操作.js

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

我希望Microsoft将来会开发此功能。

感谢Enet。

我找到了一个简单的解决方案,我认为这是最简单的选择。 创建一个自定义组件,该组件将成为您的提交按钮:

<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();
}
}
}
}
}
}

此组件充当提交按钮,但由于其类型不是提交,因此 Enter 不会触发它。它接受 EditContext 类型的级联参数,该参数允许它验证表单。它还接受一个委托,该委托将在单击时触发,并且表单状态有效。

使用示例:

<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>

这是我的解决方案。相当精益的代码,没有js。这样,您就不会直接阻止 Enter 键的默认行为。相反,您可以控制表单是否应根据 Enter 键事件继续提交。

在编辑表单声明中

<EditForm OnValidSubmit="@Submit" @onkeydown="HandleKeyDown">

在您的代码中:

private bool allowFormSubmit = true;
protected void HandleKeyDown(KeyboardEventArgs args)
{
allowFormSubmit = !(args.Key == "Enter");
}
protected async Task Submit()
{
//consume the Enter key and reset to allow form submission on submit click
if (!allowFormSubmit)
{
allowFormSubmit = true;
return;
}
//Your submit code
}

首先,您应该了解浏览器在这种情况下的行为方式。 如果表单中有<button type="submit">,并且用户按 Enter 键,浏览器将在按钮上模拟click事件。

与其取消按键事件,不如使用带有capture: trueaddEventListener来阻止单击事件。

只需添加以下javascript:

//prevent submit on enter
document.body.addEventListener('keypress', e => {
if (e.which == ENTER && !e.target.matches('button[type=submit]')) {
/** @type {HTMLFormElement} */
const form = e.composedPath().find(e => e.matches('form'))
/** @type {HTMLButtonElement} */
const submitButton = form && form.querySelector('button[type=submit]:enabled');
if (submitButton) {
const preventSubmit = (e2) => {
e2.preventDefault();
return false;
}
// Browser emulates submit button click, when enter key is pressed, so we need to prevent that.
form.addEventListener('click', preventSubmit, { once: true, capture: true });
setTimeout(() => form.removeEventListener('click', preventSubmit, { capture: true }), 0); // better clear the eventlistener despite once:true in case the keypress propagation has been stopped by some other eventhandler
}

}
});

它适用于 Blazor Server 和 Blazor WebAssembly,无需接触现有代码。

演示:https://blazorrepl.com/repl/mvYgPhPx007ySOGe03

因此,正如其他答案中所讨论的,如果按下 Enter 键时有一个可用的提交按钮,浏览器将自动"单击"一个提交按钮,除非您使用 JS 来阻止它,或者将事件处理程序添加到每个文本框以防止它。

我扩展了Michael的答案,并创建了一个更灵活的"提交"按钮来绕过标准的提交行为。注意:这将使您的表单对可访问性不太友好。请考虑此解决方案是否适合您的项目。

SubmitButton.razor

<button type="button" @onclick="OnClick" @attributes="UnmatchedAttributes">@ChildContent</button>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
[Parameter]
public EventCallback 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 && EditContext.Validate())
{
await OnValidSubmit.InvokeAsync();
}
}
}

用法(例如 Bootstrap 类和 FontAwesome 图标)

<EditForm Model="@model">
@* Add your form elements *@
<SubmitButton class="btn btn-success" OnValidSubmit="HandleValidSubmit"><i class="fas fa-save me-2"></i>Submit</SubmitButton>
</EditForm>
@code {
private async Task HandleValidSubmit()
{
// Do your thing!
}
}

编辑:看来您需要在页面上使用另一个@onkeypress

我不得不承认以下内容比原始解决方案要复杂一些......但它对😅误导性信息感到抱歉。


<EditForm Model="exampleModel" OnValidSubmit="HandleValidSubmit" @onkeypress:preventDefault="preventDefault">
<InputText @bind-Value="exampleModel.Name1" @onkeypress="@(e => preventDefault = e.Key == "Enter")" />
<button type="submit">submit</button>
</EditForm>
@code {
public bool preventDefault { get; set; } = false;
}
<小时 /><小时 />

有点晚了,但想通了

@onkeydown:preventDefault="true"

在您的编辑表单组件中也可以解决问题。

<EditForm Model="exampleModel" @onkeydown:preventDefault="true" OnValidSubmit="HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<InputText id="name" @bind-Value="exampleModel.Name" />
<InputText id="name2" @bind-Value="exampleModel.Name2" />
<button type="submit">Submit</button>
</EditForm>

保持简单方法:

  1. 将项添加到项的类定义中,对于 WhatToDo:

    public string WhatToDo { get; set; }
    
  2. 添加一个不可见的按钮作为提交按钮中的第一个按钮,以及

  3. 在 OnSubmit 方法中测试其值。 如果用户只按 Enter 键,将返回此按钮的值。

如果它的值是(在我的例子中是"无所事事"),那么只需返回。

<EditForm..... with OnSubmit parameters>
...
<button type="submit" @onclick="@(()=> selectedItem.WhatToDo = "DoNothing")" class="btn btn-primary" style="display:none;">Do Nothing</button>
<button type="submit" @onclick="@(()=> selectedItem.WhatToDo = "Save")" class="btn btn-primary">Save</button>
<button type="submit" @onclick="@(()=> selectedItem.WhatToDo = "ExitWOSave")" class="btn btn-primary">Exit w/o Saving</button>
</EditForm>
@code {
private async Task InsertOrUpdateItem()
{
Console.WriteLine("WhatToDo is XX" + selectedItem.WhatToDo + "XX");
if (selectedItem.WhatToDo == "ExitWOSave")   //test for this first
{
// Navigate away…
return;
};
if (selectedItem.WhatToDo == "DoNothing")
{ return; }
if (selectedItem.WhatToDo == "Save")
{ //do your save…
return; 
}
}

最新更新