在具有相同ID的下拉字段列表中,验证下拉项不会出现多次

时间:2018-01-18 12:22:22

标签: c# jquery asp.net-mvc unobtrusive-validation

我有一个表单,用户可以根据需要添加任意数量的行。每次他们都希望从提供的下拉列表中选择不同的选项。目前没有任何验证可以阻止他们多次选择相同的值。

enter image description here

每一行都是“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.

}

1 个答案:

答案 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