!1964 feat(#I4E8YL): add ValidateRule parameter on ValidateBase

* refactor: 优化内部验证逻辑
* refactor: 重命名 FormItemValidator
* refactor: 不公开内部三个 Validator
* doc: 增加 EditorItem 示例
* feat: IEditorItem 接口增加 ValidateRules 属性
* doc:  增加自定义表单示例
* feat: 增加自定义验证类
* refactor: 公开现有验证类
* refactor: 重构 ValidateBase 基类开放 ValidateRules 接口
This commit is contained in:
Argo 2021-10-18 04:05:21 +00:00
parent fa1d8341e2
commit f9a8831190
16 changed files with 193 additions and 27 deletions

View File

@ -195,15 +195,44 @@
</Block>
<Block Title="表单内设置组件标签右对齐" Introduction="通过样式统一设置全站或者特定表单内标签对齐方式">
<p>地址文本框增加了 <b>邮件地址</b> 验证规则</p>
<Pre>&lt;EditorItem @@bind-Field="@@context.Address" ValidateRules="@@CustomerRules" /&gt;</Pre>
<ValidateForm Model="@Model">
<EditorForm TModel="Foo" ItemsPerRow="2" RowType="RowType.Inline" LabelAlign="Alignment.Right">
<FieldItems>
<EditorItem @bind-Field="@context.Address" ValidateRules="@CustomerRules" />
<EditorItem @bind-Field="@context.Hobby" Items="@Hobbys" />
</FieldItems>
</EditorForm>
</ValidateForm>
</Block>
<Block Title="自定义验证表单" Introduction="通过设置 <code>Rules</code> 添加自定义验证规则">
<p>地址文本框增加了 <b>邮件地址</b> 验证规则,点击提交时验证</p>
<Pre>protected override void OnInitialized()
{
base.OnInitialized();
// 增加邮箱验证规则
CustomerRules.Add(new CustomerValidator(new EmailAddressAttribute()));
// Razor 文件中使用
// &lt;BootstrapInput @@bind-Value="@@Model.Address" ValidateRules="@@CustomerRules" /&gt;
}</Pre>
<ValidateForm Model="@Model">
<div class="row g-3">
<div class="col-12 col-sm-6">
<BootstrapInput @bind-Value="@Model.Name" />
</div>
<div class="col-12 col-sm-6">
<BootstrapInput @bind-Value="@Model.Address" ValidateRules="@CustomerRules" />
</div>
<div class="col-12">
<Button ButtonType="@ButtonType.Submit" Text="提交表单" />
</div>
</div>
</ValidateForm>
</Block>
<AttributeTable Items="@GetAttributes()" />
<MethodTable Items="@GetMethods()" />

View File

@ -52,6 +52,18 @@ namespace BootstrapBlazor.Shared.Pages
[NotNull]
private ComplexFoo? ComplexModel { get; set; }
private List<IValidator> CustomerRules { get; } = new();
/// <summary>
///
/// </summary>
protected override void OnInitialized()
{
base.OnInitialized();
CustomerRules.Add(new FormItemValidator(new EmailAddressAttribute()));
}
/// <summary>
/// OnInitializedAsync 方法
/// </summary>

View File

@ -123,7 +123,7 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 获得/设置 组件自定义类型参数集合 默认为 null
/// </summary>
public IEnumerable<KeyValuePair<string, object>>? ComponentParameters { get; set; }
IEnumerable<KeyValuePair<string, object>>? IEditorItem.ComponentParameters { get; set; }
/// <summary>
/// 获得/设置 显示模板
@ -153,7 +153,7 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 获得/设置 列过滤器
/// </summary>
public IFilter? Filter { get; set; }
IFilter? ITableColumn.Filter { get; set; }
/// <summary>
/// 获得 属性类型
@ -182,6 +182,11 @@ namespace BootstrapBlazor.Components
/// </summary>
Action<TableCellArgs>? ITableColumn.OnCellRender { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
List<IValidator>? IEditorItem.ValidateRules { get; set; }
/// <summary>
///
/// </summary>

View File

@ -226,6 +226,7 @@ namespace BootstrapBlazor.Components
item.ComponentType = el.ComponentType;
item.ComponentParameters = el.ComponentParameters;
item.SkipValidate = el.SkipValidate;
item.ValidateRules = el.ValidateRules;
}
}
}

View File

@ -130,6 +130,12 @@ namespace BootstrapBlazor.Components
[Parameter]
public IEnumerable<SelectedItem>? Lookup { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
[Parameter]
public List<IValidator>? ValidateRules { get; set; }
/// <summary>
/// 获得/设置 IEditorItem 集合实例
/// </summary>

View File

@ -89,6 +89,11 @@ namespace BootstrapBlazor.Components
/// </summary>
IEnumerable<SelectedItem>? Lookup { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
List<IValidator>? ValidateRules { get; set; }
/// <summary>
/// 获取绑定字段显示名称方法
/// </summary>

View File

@ -126,6 +126,11 @@ namespace BootstrapBlazor.Components
/// </summary>
public Action<TableCellArgs>? OnCellRender { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
public List<IValidator>? ValidateRules { get; set; }
/// <summary>
/// 构造函数
/// </summary>
@ -267,6 +272,7 @@ namespace BootstrapBlazor.Components
if (source.TextEllipsis) dest.TextEllipsis = source.TextEllipsis;
if (!source.Visible) dest.Visible = source.Visible;
if (source.Width != null) dest.Width = source.Width;
if (source.ValidateRules != null) dest.ValidateRules = source.ValidateRules;
}
}
}

View File

@ -262,6 +262,12 @@ namespace BootstrapBlazor.Components
[Parameter]
public Action<TableCellArgs>? OnCellRender { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
[Parameter]
public List<IValidator>? ValidateRules { get; set; }
/// <summary>
/// 获得/设置 Table 实例
/// </summary>

View File

@ -14,7 +14,7 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 获得 Rules 集合
/// </summary>
ICollection<IValidator> Rules { get; }
List<IValidator> Rules { get; }
/// <summary>
/// 验证组件添加时回调此方法

View File

@ -364,7 +364,13 @@ namespace BootstrapBlazor.Components
/// <summary>
/// 获得 数据验证方法集合
/// </summary>
public ICollection<IValidator> Rules { get; } = new HashSet<IValidator>();
public List<IValidator> Rules { get; } = new();
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
[Parameter]
public List<IValidator>? ValidateRules { get; set; }
/// <summary>
/// 验证组件添加时调用此方法
@ -372,7 +378,7 @@ namespace BootstrapBlazor.Components
/// <param name="validator"></param>
public virtual void OnRuleAdded(IValidator validator)
{
Rules.Add(validator);
}
/// <summary>
@ -389,7 +395,31 @@ namespace BootstrapBlazor.Components
// 增加数值类型验证如 泛型 TValue 为 int 输入为 Empty 时
ValidateType(context, results);
Rules.ToList().ForEach(validator => validator.Validate(propertyValue, context, results));
// 接口验证规则
if (results.Count == 0)
{
foreach (var validator in Rules)
{
validator.Validate(propertyValue, context, results);
if (results.Count > 0)
{
break;
}
}
}
// 自定义验证集合
if (results.Count == 0 && ValidateRules != null)
{
foreach (var validator in ValidateRules)
{
validator.Validate(propertyValue, context, results);
if (results.Count > 0)
{
break;
}
}
}
}
}

View File

@ -0,0 +1,44 @@
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace BootstrapBlazor.Components
{
/// <summary>
/// 自定义验证类
/// </summary>
public class FormItemValidator : ValidatorBase
{
/// <summary>
/// 获得 ValidationAttribute 实例
/// </summary>
public ValidationAttribute Validator { get; }
/// <summary>
///
/// </summary>
/// <param name="attribute"></param>
public FormItemValidator(ValidationAttribute attribute)
{
Validator = attribute;
}
/// <summary>
/// 验证方法
/// </summary>
/// <param name="propertyValue">待校验值</param>
/// <param name="context">ValidateContext 实例</param>
/// <param name="results">ValidateResult 集合实例</param>
public override void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
{
var result = Validator.GetValidationResult(propertyValue, context);
if (result != null)
{
results.Add(result);
}
}
}
}

View File

@ -8,13 +8,23 @@ using System.Globalization;
namespace BootstrapBlazor.Components
{
class MaxValidator : IValidator
/// <summary>
/// 最大值验证实现类
/// </summary>
class MaxValidator : ValidatorBase
{
/// <summary>
/// 获得/设置 值
/// </summary>
public int Value { get; set; }
public string? ErrorMessage { get; set; }
public void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
/// <summary>
/// 验证方法
/// </summary>
/// <param name="propertyValue">待校验值</param>
/// <param name="context">ValidateContext 实例</param>
/// <param name="results">ValidateResult 集合实例</param>
public override void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
{
if (propertyValue != null && propertyValue is int v)
{

View File

@ -9,15 +9,17 @@ using System.Globalization;
namespace BootstrapBlazor.Components
{
/// <summary>
///
/// 最小值验证实现类
/// </summary>
class MinValidator : IValidator
class MinValidator : MaxValidator
{
public int Value { get; set; }
public string? ErrorMessage { get; set; }
public void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
/// <summary>
/// 验证方法
/// </summary>
/// <param name="propertyValue">待校验值</param>
/// <param name="context">ValidateContext 实例</param>
/// <param name="results">ValidateResult 集合实例</param>
public override void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
{
if (propertyValue != null && propertyValue is int v)
{

View File

@ -11,7 +11,7 @@ using System.ComponentModel.DataAnnotations;
namespace BootstrapBlazor.Components
{
/// <summary>
///
/// Required 验证实现类
/// </summary>
class RequiredValidator : ValidatorBase
{
@ -31,11 +31,11 @@ namespace BootstrapBlazor.Components
public JsonLocalizationOptions? Options { get; set; }
/// <summary>
/// 数据验证方法
/// 验证方法
/// </summary>
/// <param name="propertyValue"></param>
/// <param name="context"></param>
/// <param name="results"></param>
/// <param name="propertyValue">待校验值</param>
/// <param name="context">ValidateContext 实例</param>
/// <param name="results">ValidateResult 集合实例</param>
public override void Validate(object? propertyValue, ValidationContext context, List<ValidationResult> results)
{
var errorMessage = GetLocalizerErrorMessage(context, LocalizerFactory, Options);

View File

@ -384,30 +384,35 @@ namespace BootstrapBlazor.Components
{
builder.AddAttribute(5, nameof(ValidateBase<string>.IsDisabled), true);
}
if(item.ValidateRules != null)
{
builder.AddAttribute(6, nameof(ValidateBase<string>.ValidateRules), item.ValidateRules);
}
}
if (IsCheckboxList(fieldType) && item.Items != null)
{
builder.AddAttribute(6, nameof(CheckboxList<IEnumerable<string>>.Items), item.Items.Clone());
builder.AddAttribute(7, nameof(CheckboxList<IEnumerable<string>>.Items), item.Items.Clone());
}
// 增加非枚举类,手动设定 ComponentType 为 Select 并且 Data 有值 自动生成下拉框
if (item.Items != null && item.ComponentType == typeof(Select<>).MakeGenericType(fieldType))
{
builder.AddAttribute(7, nameof(Select<SelectedItem>.Items), item.Items.Clone());
builder.AddAttribute(8, nameof(Select<SelectedItem>.Items), item.Items.Clone());
}
// 设置 SkipValidate 参数
if (IsValidatableComponent(componentType))
{
builder.AddAttribute(8, nameof(IEditorItem.SkipValidate), item.SkipValidate);
builder.AddAttribute(9, nameof(IEditorItem.SkipValidate), item.SkipValidate);
}
builder.AddMultipleAttributes(9, CreateMultipleAttributes(fieldType, model, fieldName, item, showLabel));
builder.AddMultipleAttributes(10, CreateMultipleAttributes(fieldType, model, fieldName, item, showLabel));
if (item.ComponentParameters != null)
{
builder.AddMultipleAttributes(10, item.ComponentParameters);
builder.AddMultipleAttributes(11, item.ComponentParameters);
}
builder.CloseComponent();
}

View File

@ -123,6 +123,11 @@ namespace UnitTest.Emit
public string PlaceHolder { get; set; }
/// <summary>
/// 获得/设置 自定义验证集合
/// </summary>
public List<IValidator> ValidateRules { get; set; }
public string GetDisplayName() => Text ?? FieldName;
public string GetFieldName() => FieldName;