Mudblazor Select 具有多选和 Fluentvalidation For-Expression
我在多选模式下绑定到选择字段,并且遇到了选择字段的“For”属性的问题。
当使用选择字段时,必须设置选项类型,在本例中它将是字符串。为了使验证起作用, “For”- 需要设置属性并指向与选择字段选项类型相同的有效属性(即字符串)。 但我期待多重选择,因此我绑定到模型中的 IEnumerable
我该如何进行这项工作?我尝试构建一个自定义表达式,该表达式将指向数组的第一个元素,但我对表达式很不好,无法使其工作。
@using FluentValidation
<MudCard>
<MudForm Model="@model" @ref="@form" Validation="@(testValidator.ValidateValue)" ValidationDelay="0">
<MudCardContent>
<MudSelect T="string" Label="Name"
HelperText="Pick your favorite name" MultiSelection="false" @bind-Value="model.Name" For="() => model.Name">
@foreach (var name in _names)
{
<MudSelectItem T="string" Value="@name">@name</MudSelectItem>
}
</MudSelect>
<MudSelect T="string" Label="Names"
HelperText="Pick your favorite names" MultiSelection="true" @bind-SelectedValues="model.Names"
@* For="() => model.Names" This needs to be set to make validation work *@
>
@foreach (var name in _names)
{
<MudSelectItem T="string" Value="@name">@name</MudSelectItem>
}
</MudSelect>
</MudCardContent>
</MudForm>
<MudCardActions>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto" OnClick="@(async () => await Submit())">Order</MudButton>
</MudCardActions>
</MudCard>
@code {
[Inject] ISnackbar Snackbar { get; set; }
private string[] _names = new string[] {
"Toni", "Matthew", "David"
};
MudForm form;
TestModelFluentValidator testValidator = new TestModelFluentValidator();
TestModel model = new TestModel();
public class TestModel
{
public string Name { get; set; }
public IEnumerable<string> Names { get; set; }
}
private async Task Submit()
{
await form.Validate();
if (form.IsValid)
{
Snackbar.Add("Submited!");
}
}
/// <summary>
/// A standard AbstractValidator which contains multiple rules and can be shared with the back end API
/// </summary>
/// <typeparam name="OrderModel"></typeparam>
public class TestModelFluentValidator : AbstractValidator<TestModel>
{
public TestModelFluentValidator()
{
RuleFor(x => x.Name)
.NotEmpty();
RuleFor(x => x.Names).Must((parent, property) => property.Contains("Toni"))
.WithMessage("Toni not found in those names!");
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<TestModel>.CreateWithOptions((TestModel)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}
}
编辑:添加了代码示例并修剪了不必要的代码。
I am binding to a select field in multiselect mode and I ran into a problem with the "For" property of the select field".
When using a select field an options type must be set and in this example it will be string. To make validation work the "For"-Property needs to be set and pointing to a valid property of the same type as the select fields option (and thats string).
But I am expecting a multiselect, so I am binding to an IEnumerable<string> in my model and the validation code is also set for this property.
I don`t have the necessary property to bind to and even if I did, the validation would not work as expected.
How do I make this work? I tried building a custom expression which would point to the first element of the array, but I am bad with expressions and couldn`t make it work.
@using FluentValidation
<MudCard>
<MudForm Model="@model" @ref="@form" Validation="@(testValidator.ValidateValue)" ValidationDelay="0">
<MudCardContent>
<MudSelect T="string" Label="Name"
HelperText="Pick your favorite name" MultiSelection="false" @bind-Value="model.Name" For="() => model.Name">
@foreach (var name in _names)
{
<MudSelectItem T="string" Value="@name">@name</MudSelectItem>
}
</MudSelect>
<MudSelect T="string" Label="Names"
HelperText="Pick your favorite names" MultiSelection="true" @bind-SelectedValues="model.Names"
@* For="() => model.Names" This needs to be set to make validation work *@
>
@foreach (var name in _names)
{
<MudSelectItem T="string" Value="@name">@name</MudSelectItem>
}
</MudSelect>
</MudCardContent>
</MudForm>
<MudCardActions>
<MudButton Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto" OnClick="@(async () => await Submit())">Order</MudButton>
</MudCardActions>
</MudCard>
@code {
[Inject] ISnackbar Snackbar { get; set; }
private string[] _names = new string[] {
"Toni", "Matthew", "David"
};
MudForm form;
TestModelFluentValidator testValidator = new TestModelFluentValidator();
TestModel model = new TestModel();
public class TestModel
{
public string Name { get; set; }
public IEnumerable<string> Names { get; set; }
}
private async Task Submit()
{
await form.Validate();
if (form.IsValid)
{
Snackbar.Add("Submited!");
}
}
/// <summary>
/// A standard AbstractValidator which contains multiple rules and can be shared with the back end API
/// </summary>
/// <typeparam name="OrderModel"></typeparam>
public class TestModelFluentValidator : AbstractValidator<TestModel>
{
public TestModelFluentValidator()
{
RuleFor(x => x.Name)
.NotEmpty();
RuleFor(x => x.Names).Must((parent, property) => property.Contains("Toni"))
.WithMessage("Toni not found in those names!");
}
public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<TestModel>.CreateWithOptions((TestModel)model, x => x.IncludeProperties(propertyName)));
if (result.IsValid)
return Array.Empty<string>();
return result.Errors.Select(e => e.ErrorMessage);
};
}
}
Edit: Added code sample and trimmed unecessary code.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
mudblazor snippet。
好吧,好吧,因此,您可以通过引入多木材并结合了多个属性, - 选择该组件,然后在验证期间测试其名称。
因此当Fluent验证启动时匹配。
当表单组件将虚拟属性名称传递给验证方法时,您可以将传递的虚拟名称更改为收藏的名称,
Mudblazor snippet.
Ok, so you can trick the component by introducing a dummy property and binding the multi-select component to it then testing its name during validation.
When the form component passes the dummy property name to the validation method, you change the passed dummy name to the name of your collection so it's matched when fluent validation kicks in.
Something like this:
这是我如何避免它的解决方案。我刚刚创建了一个新组件。
然后,您可以像以下方式一样使用它:
Here is my solution for how to avoid it. I just created a new component.
Then you can use it like: