【问题标题】:Unobtrusive validation for nested collections嵌套集合的不显眼验证
【发布时间】:2014-01-18 21:21:49
【问题描述】:

由于我正在处理一个极其复杂的模型和表格,我将通过一个更易于理解的示例来减少我的问题(如果有任何错字,请原谅)。

首先我将展示场景:

模型...

public class Foo
{
    [Required]
    public int fooId {get; set;}
    public string fooName {get; set;}

    public List<Bar> barList {get; set;}
}


public class Bar
{
    [Required]
    public int barId {get; set;}
    public string barName {get; set;}
}

景色...

@model Foo

@using (Html.BeginForm("Save", "form", FormMethod.Post))
{

    <div class="control-group">  
        <div class="controls">  
            @Html.TextBoxFor(model => Model.fooId)
       </div>
    </div> 

    <div class="control-group">  
        <div class="controls">  
            @Html.TextBoxFor(model => Model.fooName)
        </div>
    </div> 

    @for (int i = 0; i < Model.barList.Count(); i++)
    { 
        @Html.EditorFor(m => m.barList[i])
    }

}

“栏”编辑器模板...

@model Bar

<div class="control-group">  
    <div class="controls">  
        @Html.TextBoxFor(m => m.barId)
    </div>
</div> 
<div class="control-group">  
    <div class="controls">  
        @Html.TextBoxFor(m => m.barName)
    </div>
</div> 

我遇到的问题是在客户端验证嵌套集合中的输入期间,在这种情况下,我无法验证“barId”输入字段。它只是忽略它...... 在 fooId 字段的情况下,它被验证 OK。

如果我们更深入,一个带有 2 个“bar”项的“foo”对象会生成如下内容:

<div class="control-group">  
    <div class="controls">  
        <input class="input-validation-error" id="fooId" name="fooId" type="text" value=""> 
    </div>
</div>
<div class="control-group">  
    <div class="controls">  
        <input id="fooName" name="fooName" type="text" value=""> 
    </div>
</div>

<div class="control-group">  
    <div class="controls">  
        <input id="barList_0__barId" name="barList[0].barId" type="text" value=""> 
    </div>
</div>
<div class="control-group">  
    <div class="controls">  
        <input id="barList_0__barName" name="barList[0].barName" type="text" value=""> 
    </div>
</div>

<div class="control-group">  
    <div class="controls">  
        <input id="barList_1__barId" name="barList[1].barId" type="text" value=""> 
    </div>
</div>
<div class="control-group">  
    <div class="controls">  
        <input id="barList_1__barName" name="barList[1].barName" type="text" value=""> 
    </div>
</div>

如您所见,“bar”集合中的项目收到了不同的 id 和名称。这是呈现集合的正常行为。

但客户端验证似乎不适用于这些 id 和名称。仅当我将 id 和名称更改为“barId”,删除集合索引时,验证才会起作用..

经过数小时的调查,我发现了一些关于此类问题的文章和帖子,但没有任何具体内容,我仍然无法解决这个问题。

IValidatableObject in MVC3 - client side validation

mvc clientside validation for nested (collection) properties

【问题讨论】:

  • 您发布的输出似乎与您的视图和编辑器模板不匹配,前两个不应该是 Foo 控件并且每个 Bar 都有 Id 和 Name 控件吗?
  • 是的,很抱歉。现在改正了
  • 如果您使用 javascript 添加您的收藏项,您是否正在刷新您的验证?例如,var form = $("#editItem"); form.removeData('validator'); form.removeData('unobtrusiveValidation'); $.validator.unobtrusive.parse(form); 是我在为集合项添加 add 方法后调用的名称。
  • 您的问题得到答案了吗?

标签: asp.net-mvc validation collections unobtrusive-validation mvc-editor-templates


【解决方案1】:

我没有找到解决方案,但我确实找到了解决方法。

功能解释:模型名为“InsuranceLine”,它有一个集合“InsuranceLine.Letters”。每个字母都有一个可为空的布尔属性“Letter.IsDeficient”。如果“IsDeficient”从 False 更改为 True,则需要字符串字段“Letter.ReasonCode”。 “IsDeficient”呈现为一个复选框,“ReasonCode”呈现为两个单选按钮,“Corrected”和“Waived”。

这是自定义属性:

    public class ReasonCodeAttribute : ValidationAttribute, IClientValidatable
    {
        private const string errorMessage = "When 'Deficient' is changed from True to False you must select a Reason.";

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            yield return new ModelClientValidationRule
            {
                ErrorMessage = errorMessage,
                ValidationType = "reasoncoderequired"
            };
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            Letter letter = validationContext.ObjectInstance as Letter;
            if(!letter.IsDeficient.GetValueOrDefault() 
                && letter.IsDeficient_OriginalState.GetValueOrDefault()
                && (value == null || string.IsNullOrEmpty(value.ToString())))
            {
                return new ValidationResult(errorMessage);
            }
            else
            {
                return null;
            }
        }
    }

我用自定义属性装饰了 Letter.ReasonCode:

[ReasonCodeAttribute]
public string ReasonCode { get; set; }

我在 *.cshtml 页面中渲染嵌套的 Letters 集合:

@for (int i = 0; i < Model.Letters.Count; i++)
{
@Html.EditorFor(m => m.Letters[i].IsDeficient, "MyCustomTemplate", new { htmlAttributes  = new { @class="cb-is-deficient" } })
<div class="rb-reason-code">
    <label>@Html.RadioButtonFor(m => m.Letters[i].ReasonCode, myVar == "C", new { id = id + "C", @class ="rb-reason-code" }) Corrected</label>
    &nbsp;&nbsp;
    <label>@Html.RadioButtonFor(m => m.Letters[i].ReasonCode, myVar == "W", new { id = id + "W", @class = "rb-reason-code" }) Waived</label>
</div>
}

ReasonCode 属性的 GetClientValidationRules() 方法导致 asp.net 运行时在将 ReasonCode 呈现为 html 单选按钮时生成以下属性:

data-val-reasoncoderequired="When 'Deficient' is changed from True to False you must select a Reason.".

在 JavaScript 中,我将 'reasoncoderequired' 方法添加到验证器,就像在文档就绪方法中一样。作为我的解决方法的一部分,我需要手动将“错误”类添加到我的显示中,以便用户获得模型无效状态的视觉提示:

$.validator.addMethod('reasoncoderequired', function (value, element) {
        var $parent = $(element).closest('div.parent');
        var $cb = $parent.find('input[type="checkbox"].cb-is-deficient');
        if ($cb.prop('defaultChecked')) {
            var $selectedRadioButton = $parent.find('div.rb-reason-code').find('input[type="radio"]:checked');
            if ($selectedRadioButton.length == 0) {
                $parent.addClass('error');
                return false;
            }
        }
        $parent.removeClass('error');
        return true;
    });

最后,我像这样将reasoncoderequired 规则添加到每个ReasonCode 单选按钮,也在文档就绪方法中。 “消息”只是从每个输入呈现的 data-val-reasoncoderequired 属性中读取以显示错误消息:

        $form.find('input[type="radio"].rb-reason-code').each(function () {
        $(this).rules('add',
            {
                reasoncoderequired: true,
                messages: { reasoncoderequired: $(this).attr('data-val-reasoncoderequired') }
            });
    })

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-04
    • 1970-01-01
    • 2016-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    相关资源
    最近更新 更多