我有一个表单,用户可以根据需要添加任意数量的行。每次他们都希望从提供的下拉列表中选择不同的选项。目前没有任何验证可以阻止他们多次选择相同的值。
每一行都是“ResourceCount”。 ViewModel有一个IList的ResourceCountViewModel,因此每一行都作为项添加到列表中。
ResourceCount视图模型包含一个“id”,用于存储所选的下拉值和数字字段的“数量”。
我想不出在这种情况下使用比较注释的方法。 如何为此实现适当的验证?
编辑: 在接受的答案中有很多好的建议。我在控制器后期操作中进行了简单的检查:
if (resourceCounts.Count != resourceCounts.Where(d => d.Id!= 0)
.Select(x => x.Id)
.Distinct()
.Count())
{
ModelState.AddModelError(string.Empty, "You can't select the same option more than once");
//etc.
}
答案 0 :(得分:2)
使用ValidationAttribute
(内置或自定义)和MVC不显眼的客户端验证是不可能的。
验证属性应用于模型(您的类)的属性,并且检查验证的上下文仅适用于该实例 - 它不知道集合中模型的其他实例,因此无法比较其他实例
相反,如果您将ValidationAttribute
应用于集合(例如List<T>
属性),则不显眼的验证将无效,因为向data-val-*
添加规则所需的$.validator
属性只有在包含集合属性的输入时才会生成(与集合中每个对象的每个属性相对),这意味着ModelBinding
将失败。
您需要编写自己的控制器代码和脚本以实现自定义验证。
在客户端,您可以处理.change()
的{{1}}事件并检查以前的选择是否匹配,如果是,则显示错误消息。您没有显示您的模型或视图,但基于以下html(对集合中的每个对象重复
<select>
然后脚本将是
<select class="select" .....>
<option value="">Please select</option>
<option value="1">On-call</option>
....
<select>
<div class="error"></div> // see notes below if you using ValidationMessageFor()
请参阅this fiddle以获取工作示例。
或者,您可以隐藏/显示(或禁用)每个var errors = $('.error');
var selects = $('.select');
$('.select').change(function() {
var selected = $.map(selects, function(s, i) {
return $(s).val();
})
$.each(selects, function(i, s) {
var error = $(this).next('.error');
var val = $(this).val();
var index = i;
if ($(this).val()) {
var others = selected.filter(function(s, i) {
if (i != index) {
return s;
}
});
if (others.indexOf(val) > -1) {
error.text('Please make a unique selection');
} else {
error.text('');
}
} else {
error.text('');
}
})
})
中的选项,以防止用户首先进行无效选择,但如果您动态添加/删除项目,和/或何时更加复杂您的视图正在编辑属性已经具有选定值的现有数据(如果您想要实现该属性,我将留给您询问显示您尝试的新问题)。
在服务器端,您可以检查重复值,如果是,则添加<select>
错误并返回视图,例如
ModelState
或使用linq
var selected = new List<int>();
for (int i = 0 i < model.Count; i++)
{
if (selected.Contains(model[i].YourProperty))
{
ModelState.AddModelError("", "Please make a unique selection");
break;
}
else
{
selected.Add(model[i].YourProperty);
}
}
if (!ModelState.IsValid)
{
return View(model);
}
....
然后将显示在视图if (model.Select(x => x.YourProperty).GroupBy(x => x).Any(g => g.Count() > 1))
{
ModelState.AddModelError("", "Please make a unique selection");
}
中。
如果您在视图中为每个下拉列表使用@Html.ValidationSummary()
,则可以将上述循环修改为
@Html.ValidationMessageFor(m => m[i].YourProperty)
并修改脚本以添加/删除if (selected.Contains(model[i].YourProperty))
{
var propertyName = string.Format("[{0}].yourPropertyName", i);
ModelState.AddModelError(propertyName, "Please make a unique selection");
break;
}
生成的<span>
元素的消息(即代替上面显示的ValidationMessageFor()
元素)
作为旁注,如果您想了解有关验证属性如何与客户端验证相结合的更多信息,建议您阅读The Complete Guide To Validation In ASP.NET MVC 3 - Part 2。