在MVC EditorTemplate中动态应用验证?

时间:2014-11-05 13:28:35

标签: c# asp.net-mvc-4 validation unobtrusive-validation data-annotations

问题 - 我的任务是在MVC中复制旧的Web窗体应用程序。我被要求保持标记类似。我不知道为什么,但你去了。那么,一般来说简单的标签和文本框会变成

<td>
    <table style="width: 100%;">
        <tr>
            <td>
                <span id='@Model.Label' class='MILabel'>
                    @Model.Name
                </span>

            </td>
            <td class="NoWrap">
                <span id='@Model.Prefix' class='Prefix'>@Model.Prefix</span>
            </td>
        </tr>
    </table>
</td>
<td class="SetDivInputWidth">
    <div id='@Model.DivId' class="NoWrap">
        @Html.TextAreaFor(m => m.Value, new
        {
            @id = Model.Name,
            @onkeyup = Model.OnKeyUp,
            @class = Model.FullClass,
            @maxlength = "100"
        }.DisabledIf(Model.IsDisabled))
        @{
            if (Model.HasGuidanceNote)
            {
                <img class="GuidanceNote" src='~/Content/Images/info.png' alt='Notes'
                     onmouseover="@Model.GuidanceNotesMouseOver"
                     onmouseout="@Model.GuidanceNotesMouseOut" />

                <span id="@Model.GuidanceNotesIdentifier" class='Info'>@Model.GuidanceNote</span>
            }}

        <img class="ErrorIcon" alt='' src='@Model.ErrorImage' id="@Model.ErrorImageId" onmouseover="@Model.ErrorImageMouseOver" onmouseout="@Model.ErrorImageMouseOut" />
        <div class="WarningText" id="@Model.WarningDivId"></div>
    </div>
</td>

这是一个用于

基本实现的自定义EditorTemplate
public class MyTextField
{
    public virtual string Name { get; set; }

    private bool _isReadOnly;

    public string Label
    {
        get { return Name + "Label"; }
    }

    public string Value { get; set; }
    public string Prefix { get; set; }
    public string CssClass { get; set; }

    public string FullClass
    {
        get { return CssClass + " " + Readonly; }
    }

    public string Readonly
    {
        get
        {
            return _isReadOnly ? "MIReadOnly" : String.Empty;
        }
    }

    public string Disabled { get; set; }

    public bool IsDisabled { get; set; }

    public bool HasGuidanceNote
    {
        get { return (GuidanceNote != null); }
    }

    public bool IsReadonly
    {
        get { return _isReadOnly; }
        set
        {
            _isReadOnly = value;
        }
    }

    public string OnKeyUp
    {
        get { return "Fields.callOnChange('" + Name + "');"; }
    }

    public string ErrorImage { get; set; }

    public string ErrorImageId
    {
        get { return Name + "ErrorIcon"; }
    }

    public string ErrorImageMouseOver
    {
        get { return "Utils.showErrorText('" + Name + "')"; }
    }

    public string ErrorImageMouseOut
    {
        get { return "Utils.clearErrorText('" + Name + "')"; }
    }

    public string DivId
    {
        get { return Name + "Div"; }
    }

    public string WarningDivId
    {
        get { return Name + "ErrorText"; }
    }

    public string GuidanceNote { get; set; }

    public string GuidanceNotesIdentifier
    {
        get { return Name + "GuidanceNotes"; }
    }

    public string GuidanceNotesMouseOver
    {
        get { return "Utils.showGuidanceNote('" + GuidanceNotesIdentifier + "')"; }
    }

    public string GuidanceNotesMouseOut
    {
        get { return "Utils.clearGuidanceNote('" + GuidanceNotesIdentifier + "')"; }
    }
}

这一切都很好。事实上,它很棒。

由于各个领域的复杂验证,问题出现了。显然,我必须在视图模型中创建MyTextField的实例(而不是它的真实名称),填充编辑器的相关字段,然后使用EditorTemplate显示。

但我无法使用DataAnnotations来验证我的数据,因为每个MyTextBox都有不同的验证规则。有些可能是必填字段,有些可能不是。有些只允许某些输入,有些则根本没有验证。 Som依赖于同一个视图中的其他字段 - 其他人不会。

有没有人有任何建议,或者我是否应该让自己手动使用JavaScript手动验证所有内容?

感谢阅读。

3 个答案:

答案 0 :(得分:0)

是的你可以使用Jquery, 在表单加载时,此脚本将向首选字段添加验证

<script>
$(document).ready(function () {
    $('#yourId').rules("add", { required: true,messages:{required:"This is required field"} });
});
</script>

如果您要删除任何事件的任何验证,请使用

$('#yourId').rules("remove");

See here

希望这有帮助!

答案 1 :(得分:0)

这个问题有很多可能的解决方案,你如何处理它取决于很多因素。

首先,如果您不需要客户端验证,您始终可以在模型上实现IValidatableObject并进行自定义验证。这很简单直接,但不能提供非常好的最终用户体验。

另一种选择是使用类似FluentValidation的东西,它允许你编写自定义验证器。

另一个选择是编写自定义DataAttributes,它们实现自己的客户端验证接口。您还必须包含一些自定义JavaScript来配置验证器。

另一个选项是简化操作,并为每个方案创建包含数据属性的自定义视图模型。如果选项的数量很大,这可能会很快变得混乱,但如果它是可管理的,这是一个相对简单的解决方案。

还有一些方法需要深入挖掘框架,我不会进入这里......但我认为你明白了......你必须决定如何进行验证并找出最佳方法。

答案 2 :(得分:0)

好吧,我找到了一个我非常满意的答案。

这是我的一个显示类,我使用隐式运算符使其有效地成为字符串。

public class RubikTextBox : AbstractField, IAbstractField
{
    public RubikTextBox(string val)
    {
        Value = val;
    }

    public static implicit operator string(RubikTextBox stringValue)
    {
        return stringValue.ToString();
    }

    public static implicit operator RubikTextBox(string stringValue)
    {
        return new RubikTextBox(stringValue);
    }

    public override string ToString()
    {
        return Value;
    }
}

它继承了一些包含其他属性的东西,抽象类特别用于吐出div ID和东西,通常可以节省我的时间和代码。

现在,为这个野兽发布HTML的EditorTemplate看起来像这样 -

<td>
    <table style="width: 100%;">
        <tr>
            <td>
                <span id='@Model.LabelName' class='MILabel'>
                    @Model.Label
                </span>

            </td>
            <td class="NoWrap">
                <span id='@Model.PrefixName' class='Prefix'>@Model.Prefix</span>
            </td>
        </tr>
    </table>
</td>
<td class="SetDivInputWidth">
    <div id='@Model.DivId' class="NoWrap">
        @Html.TextBoxFor(m => m, new
        {
            id = Model.Name,
            @class = Model.CssClass,
            maxlength = "100"
        }.DisabledIf(Model.IsDisabled).ReadOnlyIf(Model.IsReadonly))
        @{
            if (Model.HasGuidanceNote)
            {
                <img class="GuidanceNote" src='~/Content/Images/info.png' alt='Notes'
                     onmouseover="@Model.GuidanceNotesMouseover"
                     onmouseout="@Model.GuidanceNotesMouseOut" />

                <span id="@Model.GuidanceNoteName" class='Info'>@Model.GuidanceNote</span>
            }}
    </div>
</td>

这里真正重要的一点是

@Html.TextBoxFor(m => m

那是因为在viewmodel中这是该属性的来源,我可以执行以下操作 -

[Required(AllowEmptyStrings = false, ErrorMessage = @"Must be completed")]
public RubikTextBox MatterNumber { get; set; }

因此,复杂类的行为类似于字符串,默认的隐式属性是由DataAnnotation验证的属性。

只是为了证明它,发出的HTML是(根据F12工具)

<input name="MatterNumber" id="MatterNumber" type="text" value="ZPH007-0864475"  
data-val-required="Must be completed" data-val="true"
values="System.Collections.Generic.Dictionary`2+ValueCollection
[System.String,System.Object]"
keys="System.Collections.Generic.Dictionary`2+KeyCollection
[System.String,System.Object]" count="3">

目前我已经将它用于主要返回值的复杂类 复选框(可空) 货币(可以为空) DateTime(可空) 单选按钮列表 下拉列表(字符串) 短文本(文本框)和长文本(TextArea)。

我很高兴。