问题描述
所以我对某些提交逻辑在 Blazor Server 中的工作方式感到有些困惑(可能与 Blazor WebAssembly 的情况相同)。
我有一个带有字段和提交按钮(提交类型)的 EditForm:
<EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<label for="firstName" class="form-label">First Name</label>
<InputText class="form-control" @bind-Value="_formModel.FirstName" />
<button type="submit" class="btn btn-primary">New Person</button>
</EditForm>
@code {
private void HandleValidSubmit()
{
System.Diagnostics.Debug.WriteLine("SUBMIT!");
}
private class FormModel
{
[required(AllowEmptyStrings = false,ErrorMessage = "Provide a first name")]
public string FirstName{ get; set; }
}
}
在浏览器中,我执行以下操作:
- 提供将根据我的
FormModel
和DataAnnotationsValidator
评估为无效的输入,单击按钮即可告知我。这是意料之中的。 - 我更正了名字文本输入的值,并且它仍然在浏览器中获得焦点,我点击
Submit
- 所有发生的事情是 DataValidation 似乎已经运行(很酷,这总是好的),但是单击
Submit
按钮似乎从未触发我运行 OnValidSubmit 的 C# 代码。 (如您在我的示例中所见,我使用Debug.WriteLine
有没有办法在使用 OnSubmit/OnInvalidSubmit/OnValidSubmit 和 type="submit" 的按钮保持 EditForm 的同时避免这种情况?
(我读到在 Blazor 和 State 更新中使用 submit
类型的按钮与 button
类型的按钮有一点不同……不知道这是否是这里的一个因素)
从用户的角度来看,他们为一次操作按了两次按钮。这当然会让人感觉有点奇怪或令人困惑。
从我的测试来看,这似乎是涉及 DataAnnotationsValidator 的情况,这部分是有意义的,直到需要在客户端上按下两个按钮才能实际点击我的 C# 代码。 (即我知道当焦点改变时会发生数据验证)
我觉得我部分误解了一些东西,部分缺少一些额外的代码或表单中的设置以避免这种情况发生。
有没有办法在保留 DataAnnotationsValidator
的同时做我想做的事情?
在此先感谢您的帮助!
解决方法
我认为发生的事情是当您“单击”按钮(显示验证消息)时,首先发生的是输入控件失去焦点。这会导致验证事件 - 数据条目通过验证,ValidationSummary
更新并消失。渲染事件将按钮分流到页面上,因此当浏览器应用单击事件时,它位于屏幕的空白处,而不是按钮上。在下面的测试代码中,我在 ValidationSummary
上方添加了一个提交按钮,它可以工作,因为它不会移动。它发生得如此之快,你会错过它!
对此的一种解决方法是更改输入的行为以验证数据输入而不是失去焦点。
这是一个自定义 InputText
控件:
@namespace MyNameSpace
@inherits InputText
<input type="text" value="@this.CurrentValue" @oninput="OnInput" @ref="Element" />
@code{
public ElementReference? Element { get; set; }
private void OnInput(ChangeEventArgs e)
=> this.CurrentValueAsString = e.Value.ToString();
}
它和原来的唯一区别在于响应事件现在设置为“oninput”而不是“onchange”。
测试页面如下所示。两个版本的控件都会显示出来,因此您可以看到不同的行为。
@page "/Test2"
<EditForm EditContext="@_editContext" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="HandleInValidSubmit">
<DataAnnotationsValidator />
<div class=" m-2 p-2">
<button type="submit" class="btn btn-primary">New Person</button>
</div>
<ValidationSummary />
<label class="form-label">First Name (Only Updates on Exit)</label>
<InputText class="form-control" @bind-Value="this._formModel.FirstName"></InputText>
<label class="form-label">First Name (Updates on Typing)</label>
<InputTextOnInput class="form-control" @bind-Value="this._formModel.FirstName"></InputTextOnInput>
<button type="submit" class="btn btn-primary">New Person</button>
</EditForm>
<div class="m-3 p-3">@_submitType</div>
@code {
private EditContext? _editContext;
private FormModel _formModel;
private string _submitType;
private void HandleValidSubmit()
{
_submitType = "VALID SUBMIT!";
System.Diagnostics.Debug.WriteLine("VALID SUBMIT!");
}
private void HandleInValidSubmit()
{
_submitType = "INVALID SUBMIT!";
System.Diagnostics.Debug.WriteLine("INVALID SUBMIT!");
}
private class FormModel
{
[Required(AllowEmptyStrings = false,ErrorMessage = "Provide a first name")]
public string FirstName { get; set; }
}
protected override Task OnInitializedAsync()
{
_formModel = new FormModel();
_editContext = new EditContext(_formModel);
return base.OnInitializedAsync();
}
}