MVC Unobtrusive自定义规则仅在客户端上以一种形式工作

时间:2016-10-04 20:54:44

标签: asp.net-mvc unobtrusive-validation asp.net-mvc-validation

我为MVC 5应用上的一个特定字段构建了自定义验证规则。它在编辑表单上运行良好,但在“创建”表单上验证相同字段时,客户端验证不会触发 - 触发客户端验证,但在创建表单上显示虽然我可以看到它不是有效的,所以没有显示任何消息。

两种形式都使用相同的模型。 这些脚本添加在_layout页面中,因此两个视图都包含所有脚本。 两个视图都具有完全相同的剃刀代码,包括ValidationMessageFor()

当表单到达控制器时,由于自定义错误,模型无效。所以验证工作在服务器端,而不是客户端。我找不到任何可以使它以一种形式工作而不能另一种形式工作的东西。

这是我的代码:

自定义属性:

public class AtLeastOneRequiredAttribute : ValidationAttribute, IClientValidatable
{
    public string OtherPropertyNames;

    public AtLeastOneRequiredAttribute(string otherPropertyNames)
    {
        OtherPropertyNames = otherPropertyNames;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string[] propertyNames = OtherPropertyNames.Split(',');
        bool IsAllNull = true;
        foreach(var i in propertyNames)
        {
            var p = validationContext.ObjectType.GetProperty(i);
            var val = p.GetValue(validationContext.ObjectInstance, null);
            if(val != null && val.ToString().Trim() != "")
            {
                IsAllNull = false;
                break;
            }
        }

        if(IsAllNull)
        {
            return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
        }
        else
        {
            return null;
        }
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rules = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.DisplayName),
            ValidationType = "atleastonerequired"
        };
        rules.ValidationParameters["otherpropertynames"] = OtherPropertyNames;
        yield return rules;
    }
}

客户代码:

$(function() {
    $.validator.unobtrusive.adapters.addSingleVal("atleastonerequired", "otherpropertynames");
    $.validator.addMethod("atleastonerequired", function (value, element, params) {
        var param = params.toString().split(',');
        var IsAllNull = true;
        $.each(param, function (i, val) {
            var valueOfItem = $('#Activity_' + val).val().trim();
            if (valueOfItem != '') {
                IsAllNull = false;
                return false;
            }
        });
        if (IsAllNull) {
            return false;
        }
        else {
            return true;
        }
    })
})

查看 - 编辑&amp;创建表单是相同的:

@using (Html.BeginForm("Edit", "Activity", FormMethod.Post, new { @id = "editActivityForm" }))
{
    @Html.AntiForgeryToken()

    <div class="form activity-form">
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Activity.RecordId)


        <div class="form-group">
            @Html.LabelFor(model => model.Activity.Acres, htmlAttributes: new { @class = "control-label" })
            @Html.EditorFor(model => model.Activity.Acres, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Activity.Acres, "", new { @class = "text-danger" })
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Activity.Volume, htmlAttributes: new { @class = "control-label" })
            @Html.EditorFor(model => model.Activity.Volume, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Activity.Volume, "", new { @class = "text-danger" })
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Activity.Feet, htmlAttributes: new { @class = "control-label" })
            @Html.EditorFor(model => model.Activity.Feet, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Activity.Feet, "", new { @class = "text-danger" })
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Activity.Hours, htmlAttributes: new { @class = "control-label" })
            @Html.EditorFor(model => model.Activity.Hours, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Activity.Hours, "", new { @class = "text-danger" })
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Activity.Comment, htmlAttributes: new { @class = "control-label" })
            @Html.EditorFor(model => model.Activity.Comment, new { htmlAttributes = new { @class = "form-control" } })
            @Html.ValidationMessageFor(model => model.Activity.Comment, "", new { @class = "text-danger" })
        </div>

        <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" onclick="$.validator.unobtrusive.parse($('#editActivityForm'));" />
        </div>
    </div>
}

添加了attirbute的模型:

    [AtLeastOneRequired("Acres,Volume,Feet,Hours", ErrorMessage = "Activity requires at least one measure - Acres, Volume, Feet or Hours.")]
    public Nullable<int> Acres { get; set; }
    public Nullable<int> Volume { get; set; }
    public Nullable<int> Feet { get; set; }
    public Nullable<int> Hours { get; set; }

1 个答案:

答案 0 :(得分:1)

问题在于客户端代码。我终于发现客户端代码没有被点击。我最终发现这是因为验证添加内部(function(){})。我删除了准备好的&#39;这件事现在每次都有效。