BlazorWebAssemblyでAnt Design Blazorを触っています。
Ant Design Blazorは、コンポーネントの数が多く、ドキュメントの内容が濃いので、
お気に入りのUIフレームワークです。見た目もおしゃれで、胸熱です。
既にカスタム検証が実装済の状態で、Ant Design Blazorでどうやって適応させるのかつまずいてしまったので、現段階の解決策を書いてみようと思います。
他にいい方法があれば、コメントで教えてください
バージョンなど
- .NET 8.0.204
- Microsoft.AspNetCore.Components.WebAssembly 8.0.4
- AntDesign 0.18.3
カスタム検証の内容
1.カスタム検証
public class RequiredCustomValidation : ValidationAttribute
{
protected override ValidationResult IsValid(object? value, ValidationContext context)
{
if(value is null || string.IsNullOrEmpty(value.ToString()))
{
var propertyName = ReflectionHelper.GetPropertyName(context);
return new ValidationResult($"{propertyName}は必須項目です", new[] { propertyName });
}
return ValidationResult.Success!;
}
}
2. プロパティ名取得
public static class ReflectionHelper
{
public static string GetPropertyName(ValidationContext context)
{
var member = context.ObjectInstance as MemberExpression;
if (member is null)
{
return context.DisplayName;
}
var property = member.Member as PropertyInfo;
if (property is null)
{
return context.DisplayName;
}
return property.Name;
}
}
画面の実装
@page "/form"
<Card>
<Body>
<Form Model="UserVM" TModel="User" LabelColSpan="4" WrapperColSpan="16">
<FormItem>
<Input @bind-Value="UserVM.Email"></Input>
</FormItem>
<FormItem>
<Input @bind-Value="UserVM.Password"></Input>
</FormItem>
<FormItem WrapperColOffset="4" WrapperColSpan="16">
<Button Type="@ButtonType.Primary">Submit</Button>
</FormItem>
</Form>
</Body>
</Card>
public partial class FormComponent
{
private User UserVM { get; set; } = new();
public class User
{
[DisplayName("メールアドレス")]
public string Email { get; set; }
[DisplayName("パスワード")]
public string Password { get; set; }
}
}
実装
Ant Design Blazorの導入については、公式ドキュメントに記載があるので割愛します。
1.カスタム検証をAnt Design Blazorで使用できるように修正
IsValid
とFormatErrorMessage
をAnt Design Blazorで使用できるように関数を分割化しました。
通常の場合は、IsValid(object? value, ValidationContext context)
が呼ばれる想定です。
public class RequiredCustomValidation : ValidationAttribute
{
protected override ValidationResult IsValid(object? value, ValidationContext context)
{
if(IsValid(value))
{
var propertyName = ReflectionHelper.GetPropertyName(context);
return new ValidationResult(FormatErrorMessage(propertyName));
}
return ValidationResult.Success!;
}
public override bool IsValid(object? value)
{
return value is null || string.IsNullOrEmpty(value.ToString());
}
public override string FormatErrorMessage(string name)
{
return string.Format("{0}は必須項目です", name);
}
}
2.ValidtionRulesの実装
Ant Design Blazorの場合は、プロパティに属性として追加するのではなく、
ルールを定義し、定義したルールをformItem
に設定することでValidationの設定ができます。
メールアドレスの検証ルールをRequiredCustomValidation
を呼び出して設定することで、
検証ルールの共通化が図れます。
private FormValidationRule[] emailRules = new FormValidationRule[]{
new FormValidationRule { Validator = (validationContext) => {
var validationAttribute = new RequiredCustomValidation();
if (validationAttribute.IsValid(validationContext.Value))
{
string errorMessage = validationAttribute.FormatErrorMessage(validationContext.DisplayName);
var result = new ValidationResult(errorMessage, new string[] { validationContext.FieldName });
return result;
}
return null;
}
},
};
formにValidateMode="@FormValidateMode.Rules"
を設定することで、
検証ルールでvalidationを行うことを設定できます。
formItemに先ほど作成したemailRules
を設定し、準備は完了です。
@page "/form"
<Card>
<Body>
<Form Model="UserVM" TModel="User" LabelColSpan="4" WrapperColSpan="16" ValidateMode="@FormValidateMode.Rules">
<FormItem Rules="@(emailRules)">
<Input @bind-Value="UserVM.Email"></Input>
</FormItem>
<FormItem>
<Input @bind-Value="UserVM.Password"></Input>
</FormItem>
<FormItem WrapperColOffset="4" WrapperColSpan="16">
<Button Type="@ButtonType.Primary" HtmlType="submit">Submit</Button>
</FormItem>
</Form>
</Body>
</Card>
結果
下記のように、submitボタンクリック時に検証が走り、
検証ルールに設定した検証が実行されていることを確認しました。
補足
formにValidateMode="@FormValidateMode.Rules"
と設定すると、Attribute属性にRequiredを設定していても、必須マークが設定されなくなってしまいます。
そのため、formItemにRequired
の設定をして必須マークを付与してください。
<FormItem Rules="@(emailRules)" Required>
<Input @bind-Value="UserVM.Email"></Input>
</FormItem>
最後に
フロントエンドとサーバーサイドで検証ルールを共通化できるよう、
UIフレームワークでも検証ルールの設定方法を考えてみました。
やっていることは、とても単純なのですが、
一度沼にはまると、なかなか思いつかなかったので、
今後のためにも記録していきたいと思います。
まだまだ初心者のため、その他最善策などありましたらコメントお願いします!