ASP.Net MVC 3 - エディター テンプレートのクライアント側での目立たない検証
質問
私は ASP.Net MVC 3 を初めて使用しますが、カスタム方法で日付を表示するために作成したエディター テンプレートのクライアント側で目立たない検証を実装しようとしているときに、いくつかの問題に直面しました。
UI
日付を表示する必要があります 3 つのテキストボックス UI としてフォーマットする
を載せました エディタテンプレート 日付を次のように 3 つの部分に分けて表示します。
@model DateTime?
<table class="datetime">
<tr>
<td>@Html.TextBox("Day", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
<td class="separator">/</td>
<td>@Html.TextBox("Month", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
<td class="separator">/</td>
<td>@Html.TextBox("Year", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
</tr>
<tr>
<td class="label">dd</td>
<td/>
<td class="label">mm</td>
<td/>
<td class="label">yyyy</td>
</tr>
</table>
モデル
のプロパティである生年月日フィールドをバインドする必要があります。 サブオブジェクト この構造内のこのプロパティにモデルを追加
MyModel
--> MySubModel
--> DateOfBirth
public class MySubModel
{
...
[DataType(DataType.Date)]
[Display(Name = "Date of birth")]
[DateTimeClientValidation()]
public DateTime DateofBirth { get; set; }
...
}
クライアントサイドの検証
IClientValidatable を実装するカスタム検証属性を設定しました。
public class DateTimeClientValidationAttribute : ValidationAttribute, IClientValidatable
{
...
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
List<ModelClientValidationRule> clientRules = new List<ModelClientValidationRule>();
//Combined date should be valid
ModelClientValidationRule validDateRule = new ModelClientValidationRule
{
ErrorMessage = "Please enter a valid date.",
ValidationType = "validdate"
};
validDateRule.ValidationParameters.Add("dayelement", metadata.PropertyName + ".Day");
validDateRule.ValidationParameters.Add("monthelement", metadata.PropertyName + ".Month");
validDateRule.ValidationParameters.Add("yearelement", metadata.PropertyName + ".Year");
clientRules.Add(validDateRule);
return clientRules;
}
...
}
ここで日、月、年のテキストボックスの要素名をクライアント側の検証要素に出力しようとしています。そのため、後でこれらの要素を消費してクライアント側で検証を行うクライアント側の jQuery 検証メソッドとアダプターを作成します。
ビュー
ここで、このエディター テンプレートを使用するために、次のように入力します。 ビュー 次の行
@model MyModel
...
<tr>
<td class="editor-label">
@Html.LabelFor(m => m.MySubModel.DateofBirth)
</td>
<td class="editor-field">
@Html.EditorFor(m => m.MySubModel.DateofBirth)
@Html.ValidationMessageFor(m => m.MySubModel.DateofBirth)
</td>
</tr>
...
関連するすべての jquery 検証ファイルを参照としてビューに追加しました
質問
- これは、HTML内で控えめなJavaScript検証属性を出力していませんが、実装しました。 IClientValidatable. 。同じ属性を入れたときのテスト目的 (日時クライアント検証) このエディター テンプレートを使用していないモデル内の別のプロパティで検証属性を出力すると、このエディター テンプレートに対してのみ出力されません。どこで間違ったのでしょうか?
- エディター テンプレートの検証メッセージ スパンについては、表示のみに置くのが正しいですか、それともエディター テンプレートに直接置くべきですか (@Html.ValidationMessageFor(m => m.MySubModel.DateofBirth))
- この例では、私が入れたデザインは正しいですか? DateTimeClientValidationAttribute, これは実際にはモデルに付けた属性ですが、このコンポーネントは UI について少し知っています (日、月、年の要素名をクライアントに出力しようとしているため)。これにより、モデルはビューについて少し知ることができます。ここで何か設計原則に違反していますか?
- で DateTimeClientValidationAttribute, 、クライアントスクリプトで検証できるように、日、月、年の要素名をクライアントに出力しようとしています。しかし、モデルプロパティ以来、 生年月日 がサブオブジェクト内にある場合、スクリプト内の実際の要素名は次のとおりです。 MySubObject.DateOfBirth, これにより、Day テキストボックスの名前が次のようになります。 MySubObject.DateofBirth.Day, 、その完全修飾モデル名を GetClientValidationRules メソッドを使用して、クライアントに名前を出力できるようにしますか?
辛抱強く最後まで読んでいただき、ご回答いただきありがとうございました
解決
苦労した結果、コントロールが機能するようになり、誰かにとって役立つかどうかを判断しました。
最初のポイントは、コントロールを次のように定義することです。
@model DateTime?
<table class="datetime">
<tr>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
<td class="separator">/</td>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
<td class="separator">/</td>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
</tr>
<tr>
<td class="label">dd</td>
<td/>
<td class="label">mm</td>
<td/>
<td class="label">yyyy</td>
</tr>
</table>
必ず与えてください 名前として空の文字列 3 つのテキストボックスすべてに同じ内容を生成すると、MVC フレームワークは強制的に同じものを生成します。 名前 モデルに対応 生年月日 クライアント側の 3 つのテキストボックスすべてに対して。また、リスト内の最初のテキストボックスには、モデルの名前を持つ編集コントロールが最初に出現するため、目立たない JavaScript 検証パラメータが生成されます。
クライアント側では、これら 3 つのテキストボックスはすべて同じ名前を持っているため、これらのテキストボックスのいずれかのイベントが発生すると、関連する検証イベントがすべて起動されます。
必要な定期的な検証に加えて、...これら 3 つの値をすべて組み合わせて、その組み合わせた値が有効な日付を形成するかどうかをチェックするカスタム クライアント検証ルーチンを作成する必要があります。これは次のようにして実現できます。 答え によって与えられた ジェフ.
他のヒント
さて、いくつかのことを。まず、可能であれば、日付を 3 つのフィールドに分割しないでください。いくつかの検証と、場合によっては jQueryUI の DatePicker を使用して単一のフィールドとして設定するだけで、煩わしい煩わしさから解放されます。
次に、DateTimeClientValidationAttribute 内のカスタム属性コードでは、IsValid を実装して日付が有効かどうかを実際にチェックすることはありません。
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
...
// Put date parts together and check is valid...
if (DateTime.TryParse(year+"/"+month+"/"+day, out dateResult))
return ValidationResult.Success;
// Not valid
return new ValidationResult(String.Format(ErrorMessageString,
validationContext.DisplayName));
}
次に、目立たない検証アダプターと、パラメータをまとめて日付の解析を試みる jQuery バリデーター メソッドを作成する必要があります。
jQuery.validator.unobtrusive.adapters.add(
'validdate', // notice this is coming from how you named your validation rule
['dayelement'],
['monthelement'],
['yearelement']
function (options) {
options.rules['datepartcheck'] = options.params;
options.messages['datepartcheck'] = options.message;
}
);
jQuery.validator.addMethod('datepartcheck', function (value, element, params) {
var year = params[2];
var month = params[1];
var day = params[0];
var birthDate = year + '/' + month-1 + '/' + day;
var isValid = true;
try {
// datepicker is a part of jqueryUI.
// include it and you can take advantage of .parseDate:
$.datepicker.parseDate('yy/mm/dd', birthDate);
}
catch (error) {
isValid = false;
}
return isValid;
}, '');