嵌套集合的无提示验证



由于我处理的是一个极其复杂的模型和表单,我将用一个更容易理解的例子来减少我的问题(如果有任何拼写错误,请原谅)。

首先,我将展示场景:

模型。。。

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&name设置为"barId",删除集合索引。。

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

IValidatableObject在MVC3中-客户端验证

嵌套(集合)属性的mvc客户端验证

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

功能解释:该模型被称为"InsuranceLine",它有一个集合"Insurance Line.Letters"。每个Letter都有一个可为null的布尔属性"Letter.IsDiscient"。如果"IsDefient"从False更改为True,则需要字符串字段"Letter.ResoreasonCode"。"IsDeficient"呈现为复选框,"ReasonCode"呈现为两个单选按钮,"Corrected"one_answers"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;
}
}
}

我装饰信件。具有自定义属性的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中,我将"reasoncoderequised"方法添加到验证器中,就像在文档就绪方法中一样。作为解决方法的一部分,我需要手动将类"error"添加到我的显示中,以便用户获得模型无效状态的视觉提示:

$.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单选按钮中,也是在文档就绪方法中。"消息"只是从每个输入呈现的数据值中读取所需属性,以显示错误消息:

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

最新更新