如何使输入组件验证输入并调用指定的回调?
How to make an input component validate input and call a specified callback?
我想要这样的东西:
<input id=filterString type="number" class="form-control" value="@FilterModel.FilterString" @oninput="@FilterChanged" />
但 InputNumber, to make use of validation.
到目前为止,我遇到的最简单和最接近的解决方案(也许?)可能是创建 InputBase 的子类的方法,将指定的回调作为参数传递,并同时调用 InputBase 的 ValueChanged
被调用。类似于 this post.
我无法让它工作(我不记得具体的错误,但如果这个方法被推荐,以后可以找回它们),在反复排除故障后,它开始感觉笨拙。我已经搜索了文档,但仍然不明白验证系统和绑定是如何组合在一起的。所以我有点迷路了,如果能帮我整理一下,我将不胜感激。
总结一下:
- 我想知道实现
InputNumber
(或等效)的最简单方法,我还可以指定一个 OnInput
(或等效)回调,以便在值更改时执行一些工作.
- 如果有人可以简要地 clarify/describe 更改输入时发生的事件序列(即从用户与输入交互开始的“管道”看起来像什么),那也很好.特别是,when/where InputBase 是否进行验证? (我想我真的很困惑 InputBase(和 children)和验证是如何工作的,所以我在扩展它们时遇到了麻烦)。
谢谢,非常感谢大家的帮助。
您可以创建自己的组件并接收 EditContext
类型的级联参数 - 然后您可以使用该参数调用验证,并获取您的字段的任何验证消息。
现在您已经完全控制了输入,您可以连接到它的 @oninput
方法并完成您的工作(引发其他事件,做更多的逻辑,调用编辑的 .Validate()
方法上下文)。
您可能需要添加更多参数以允许值表达式,可能是类型参数,可能是字段名称的标识符,诸如此类,以使其更具可重用性和通用性,但核心是获得编辑上下文并控制您自己的渲染和事件。
编辑:添加示例 - 请注意,这只是一种实现,既不通用,也不完美
main component with the form
@using System.ComponentModel.DataAnnotations
<EditForm Model="@TheModel">
<DataAnnotationsValidator></DataAnnotationsValidator>
@TheModel.MyProperty
<br />
<MyNumberInput @bind-Value="@TheModel.MyProperty"
MySpecialEvent="@MySpecialEventHandler"
FieldId="@( new FieldIdentifier(TheModel, nameof(MyFormModel.MyProperty)) )" />
<ValidationMessage For="@( () => TheModel.MyProperty )"></ValidationMessage>
</EditForm>
@code{
MyFormModel TheModel { get; set; } = new MyFormModel();
async Task MySpecialEventHandler(DateTime time)
{
Console.WriteLine($"special event fired at: {time.Millisecond}");
}
public class MyFormModel
{
[Required]
[Range(3, 5)]
public int? MyProperty { get; set; }
}
}
child component - MyNumberInput
@implements IDisposable
<input type="number" @oninput="@OnInputHandler" value="@Value" />
@code {
[CascadingParameter]
public EditContext TheEditContext { get; set; }
[Parameter]
public FieldIdentifier FieldId { get; set; }
[Parameter]
public int? Value { get; set; }
[Parameter]
public EventCallback<int?> ValueChanged { get; set; }
[Parameter]
public EventCallback<DateTime> MySpecialEvent { get; set; }
async Task OnInputHandler(ChangeEventArgs e)
{
try
{
int val = int.Parse(e.Value.ToString());
Value = val;
}
catch
{
Value = null;
}
//twoway binding
await ValueChanged.InvokeAsync(Value);
//update validation - AFTER the value is saved in the form
TheEditContext.NotifyFieldChanged(FieldId);
//your own event as needed
await MySpecialEvent.InvokeAsync(DateTime.Now);
}
//some general update that may not be needed but might help if other fields update this one and you need to rerender
void ValidationStateChanged(object sender, ValidationStateChangedEventArgs e)
{
StateHasChanged();
}
protected override void OnInitialized()
{
if (TheEditContext != null)
TheEditContext.OnValidationStateChanged += ValidationStateChanged;
}
public void Dispose()
{
if (TheEditContext != null)
TheEditContext.OnValidationStateChanged -= ValidationStateChanged;
}
}
事件的顺序是这样的
- 用户键入一个字符
- 输入组件在写入时做出反应(通常可以是 oninput 或 onchange DOM 事件 - 顺便说一句,标准组件使用 onchange)
- 编辑上下文收到字段更改通知并调用验证 - 它作为级联参数出现
我想要这样的东西:
<input id=filterString type="number" class="form-control" value="@FilterModel.FilterString" @oninput="@FilterChanged" />
但 InputNumber, to make use of validation.
到目前为止,我遇到的最简单和最接近的解决方案(也许?)可能是创建 InputBase 的子类的方法,将指定的回调作为参数传递,并同时调用 InputBase 的 ValueChanged
被调用。类似于 this post.
我无法让它工作(我不记得具体的错误,但如果这个方法被推荐,以后可以找回它们),在反复排除故障后,它开始感觉笨拙。我已经搜索了文档,但仍然不明白验证系统和绑定是如何组合在一起的。所以我有点迷路了,如果能帮我整理一下,我将不胜感激。
总结一下:
- 我想知道实现
InputNumber
(或等效)的最简单方法,我还可以指定一个OnInput
(或等效)回调,以便在值更改时执行一些工作. - 如果有人可以简要地 clarify/describe 更改输入时发生的事件序列(即从用户与输入交互开始的“管道”看起来像什么),那也很好.特别是,when/where InputBase 是否进行验证? (我想我真的很困惑 InputBase(和 children)和验证是如何工作的,所以我在扩展它们时遇到了麻烦)。
谢谢,非常感谢大家的帮助。
您可以创建自己的组件并接收 EditContext
类型的级联参数 - 然后您可以使用该参数调用验证,并获取您的字段的任何验证消息。
现在您已经完全控制了输入,您可以连接到它的 @oninput
方法并完成您的工作(引发其他事件,做更多的逻辑,调用编辑的 .Validate()
方法上下文)。
您可能需要添加更多参数以允许值表达式,可能是类型参数,可能是字段名称的标识符,诸如此类,以使其更具可重用性和通用性,但核心是获得编辑上下文并控制您自己的渲染和事件。
编辑:添加示例 - 请注意,这只是一种实现,既不通用,也不完美
main component with the form
@using System.ComponentModel.DataAnnotations
<EditForm Model="@TheModel">
<DataAnnotationsValidator></DataAnnotationsValidator>
@TheModel.MyProperty
<br />
<MyNumberInput @bind-Value="@TheModel.MyProperty"
MySpecialEvent="@MySpecialEventHandler"
FieldId="@( new FieldIdentifier(TheModel, nameof(MyFormModel.MyProperty)) )" />
<ValidationMessage For="@( () => TheModel.MyProperty )"></ValidationMessage>
</EditForm>
@code{
MyFormModel TheModel { get; set; } = new MyFormModel();
async Task MySpecialEventHandler(DateTime time)
{
Console.WriteLine($"special event fired at: {time.Millisecond}");
}
public class MyFormModel
{
[Required]
[Range(3, 5)]
public int? MyProperty { get; set; }
}
}
child component - MyNumberInput
@implements IDisposable
<input type="number" @oninput="@OnInputHandler" value="@Value" />
@code {
[CascadingParameter]
public EditContext TheEditContext { get; set; }
[Parameter]
public FieldIdentifier FieldId { get; set; }
[Parameter]
public int? Value { get; set; }
[Parameter]
public EventCallback<int?> ValueChanged { get; set; }
[Parameter]
public EventCallback<DateTime> MySpecialEvent { get; set; }
async Task OnInputHandler(ChangeEventArgs e)
{
try
{
int val = int.Parse(e.Value.ToString());
Value = val;
}
catch
{
Value = null;
}
//twoway binding
await ValueChanged.InvokeAsync(Value);
//update validation - AFTER the value is saved in the form
TheEditContext.NotifyFieldChanged(FieldId);
//your own event as needed
await MySpecialEvent.InvokeAsync(DateTime.Now);
}
//some general update that may not be needed but might help if other fields update this one and you need to rerender
void ValidationStateChanged(object sender, ValidationStateChangedEventArgs e)
{
StateHasChanged();
}
protected override void OnInitialized()
{
if (TheEditContext != null)
TheEditContext.OnValidationStateChanged += ValidationStateChanged;
}
public void Dispose()
{
if (TheEditContext != null)
TheEditContext.OnValidationStateChanged -= ValidationStateChanged;
}
}
事件的顺序是这样的
- 用户键入一个字符
- 输入组件在写入时做出反应(通常可以是 oninput 或 onchange DOM 事件 - 顺便说一句,标准组件使用 onchange)
- 编辑上下文收到字段更改通知并调用验证 - 它作为级联参数出现