8

ASP.Net MVC 3を初めて使用する場合、カスタムの方法で日付を表示するために作成したエディターテンプレートに対して、クライアント側の控えめな検証を実装しようとしているときに、いくつかの問題に直面します。

UI
日付を3つのtexboxUI形式で次のように表示する必要があります

ここに画像の説明を入力してください


日付を3つの部分に分けて表示するため のEditorTemplateを作成しました。

@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;
    }
    ...
}

ここで、Day、Month、Yearテキストボックスの要素名をクライアント側の検証要素に送信しようとしています。これにより、後でこれらの要素を使用してクライアント側で検証を行うクライアント側の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検証ファイルを参照として追加しました

質問

  1. IClientValidatableを実装しましたが、これはhtmlの控えめなJavaScript検証属性を出力していません。テスト目的で、このエディターテンプレートを使用していないモデルの別のプロパティに同じ属性(DateTimeClientValidation)を配置すると、それらの検証属性が出力され、このエディターテンプレートに対してのみ出力されません。どこが間違っていたのでしょうか?
  2. エディターテンプレートの検証メッセージスパンに関して、ビューのみに配置するのは正しいですか、それともエディターテンプレートに直接配置する必要があります(@ Html.ValidationMessageFor(m => m.MySubModel.DateofBirth)
  3. この例では、私はデザインに正しく含まれていますか?これは実際にはモデルに配置した属性であるDateTimeClientValidationAttributeを配置しましたが、このコンポーネントはUIについて少し知っています(Day、Month、Year要素を出力しようとしているため)クライアントの名前)、これによりModelはViewについて少し知ることができますが、ここで設計原則を破っていますか?
  4. DateTimeClientValidationAttributeで、クライアントスクリプトが検証を実行できるように、日、月、年の要素名をクライアントに出力しようとしています。ただし、モデルプロパティDateofBirthはサブオブジェクトにあるため、スクリプトの実際の要素名はMySubObject.DateOfBirthであり、Dayテキストボックス名はMySubObject.DateofBirth.Dayになります。GetClientValidationRulesメソッドで完全修飾モデル名を見つけるにはどうすればよいですか。 、クライアントに名前を出すことができるように?

このすべてを読み上げるために辛抱強く、そして答えをありがとう

4

2 に答える 2

10

少し努力した後、私はコントロールを機能させ、それがそこにいる誰かに役立つかどうかを入れました。

最初のポイントは、コントロールを次のように定義することです。

@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つのテキストボックスすべてにModelDateofBirthに対応する同じ名前を生成します。また、モデル名の編集コントロールが最初に出現するため、リストの最初のテキストボックスに対して控えめなJavaScript検証パラメーターが生成されます。

クライアント側では、これら3つのテキストボックスはすべて同じ名前であるため、これらのテキストボックスのいずれかのイベントで、関連するすべての検証イベントが発生します。

必要な通常の検証に加えて、....これら3つの値すべてを組み合わせ、組み合わせた値が有効な日付を形成するかどうかをチェックするカスタムクライアント検証ルーチンを作成する必要があります。これは、ジェフによって与えられた答えのように達成することができます。

于 2011-04-06T16:46:15.347 に答える
5

さて、いくつかのこと。まず、可能であれば、日付を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;
}, '');
于 2011-04-01T03:03:21.643 に答える