【问题标题】:ASP.Net MVC 3 - Client side unobtrusive validation for Editor TemplatesASP.Net MVC 3 - 编辑器模板的客户端不显眼验证
【发布时间】:2011-07-19 17:01:00
【问题描述】:

我是 ASP.Net MVC 3 的新手,在尝试为我为以自定义方式显示日期而创建的编辑器模板实现客户端不显眼的验证时遇到了一些问题。

用户界面
我需要以 三个 texbox UI 格式将日期显示为


我已经建立了一个 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;
    }
    ...
}

我正在尝试将此处的日、月和年文本框的元素名称发送到客户端验证元素,以便稍后我将编写客户端 jquery 验证方法和适配器,它们将使用这些元素并在客户端。

查看
现在,为了使用这个编辑器模板,我在 View 中加入了以下几行

@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. 关于编辑器模板的验证消息跨度,是只放在 View 中还是应该直接放在编辑器模板中 (@Html.ValidationMessageFor(m => m.MySubModel.DateofBirth) )
  3. 在这个例子中,我是不是在设计中,我已经放入了 DateTimeClientValidationAttribute,这实际上是我放在模型上的一个属性,但是这个组件对 UI 有点了解(因为它正在尝试向客户端发出日、月和年元素名称),这使模型对视图有所了解,我是否在这里违反了任何设计原则?
  4. DateTimeClientValidationAttribute 中,我尝试向客户端发出日、月和年元素名称,以便客户端脚本可以对其进行验证。但由于模型属性 DateofBirth 位于子对象中,因此脚本中的实际元素名称为 MySubObject.DateOfBirth,这使得 Day 文本框名称为 MySubObject。 DateofBirth.Day,如何在 GetClientValidationRules 方法中找到完全限定的模型名称,以便将名称发送给客户端?

感谢您耐心阅读所有内容并提供答案

【问题讨论】:

    标签: asp.net-mvc-3 data-annotations editortemplates unobtrusive-validation


    【解决方案1】:

    经过一番努力,我使控件起作用,如果它对那里的任何人有帮助,则将其放入。

    第一点是将控件定义为

    @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>
    

    确保,您将 空字符串作为名称 给所有三个文本框,这会强制 MVC 框架生成与模型 DateofBirth 对应的相同 名称 em> 用于客户端的所有三个文本框。此外,将为列表中的第一个文本框生成不显眼的 javascript 验证参数,因为它是具有模型名称的编辑控件的第一次出现。

    在客户端,任何这些文本框上的任何事件都会触发所有相关的验证事件,因为所有这 3 个文本框都具有相同的名称。

    除了需要的常规验证,....我们必须编写一个自定义客户端验证例程,它将所有这三个值组合并检查组合值是否形成有效日期。这可以通过Jeff 给出的answer 来实现。

    【讨论】:

    • 谢谢!我绞尽脑汁想弄清楚这一点。
    【解决方案2】:

    好的,有几件事。首先 - 如果可能的话,不要将日期分成三个字段。只需将其设置为带有一些验证的单个字段,也许还有 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;
    }, '');
    

    【讨论】:

    • 我的客户要求是推动我拆分日期控制。我不得不在 jquery 中进行一些不显眼的管道和验证才能使其工作,现在它正在工作,是的,正如你所说,这很头疼。您的答案是最接近的匹配项,因此将其标记为答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-09
    • 1970-01-01
    • 1970-01-01
    • 2013-05-28
    相关资源
    最近更新 更多