在 MVC3 中处理验证 - 每个复选框组必须选择一个复选框

Posted

技术标签:

【中文标题】在 MVC3 中处理验证 - 每个复选框组必须选择一个复选框【英文标题】:Handling validation in MVC3 - one checkbox must be selected per checkbox group 【发布时间】:2012-04-20 10:49:29 【问题描述】:

[标题应为“每个问题必须选择一个复选框”,但 SO 不允许标题中出现“问题”一词]

简单的问答形式。举一个例子,有 7 个问题。在 POST 上,我的控制器操作需要 IEnumerable<AssessmentQuestionsModel>。我的AssessmentQuestionsModel实现了IValidatableObject,我的Validate方法如下:

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)

    if (this.assessmentAnswers.Where(e => e.userAnswer == true).Count() == 0)
    
        yield return new ValidationResult("You must select at least one answer for every question");
        yield break;
    

这在视图级别工作正常 - 它返回该错误消息并将其显示在验证摘要中。问题是,它返回 7 次,每个问题一个。现在我正在使用 jQuery 来评估验证摘要 UL 并删除重复项,但这似乎是一个 hack。我做错了什么?

谢谢

[编辑 - 测试验证结果过载]

实际上,以下调用了两次。但是,它们没有分组,仍然会显示多个验证错误。

if (this.assessmentAnswers.Where(e => e.UserAnswer== true).Count() == 0)

    yield return new ValidationResult("You must select at least one answer for every question", new List<string>()  "NoAnswerMarked" );
    yield break;

[编辑 - 查看信息]

@using System.Linq
@using System.Collections.Generic
@model IList<Academy.AssessmentQuestionsModel>

@
    ViewBag.Title = "TakeAssessment";
    ViewBag.PageID = "TakeAssessment";

@section TitleBar 
    <span>
    @if(ViewBag.Status == "questions")     
        <text>Take Assessment</text>
     else 
        <text>Assessment Response</text>
    
    </span>

@section JS 
<script type="text/javascript">
    $(function () 
        if ($(".validation-summary-errors li:contains('You must select at least one answer for every question')").length > 0) 
            $(".validation-summary-errors ul")
                .find("li:contains('You must select at least one answer for every question')")
                .remove()
                .end()
                .append("<li>You must select at least one answer for every question</li>");
        
        $("#asubmit").click(function (e) 
            var hasErrors = false;
            $(".newAnswerWrapper").each(function () 
                if ($(this).find('input[type="checkbox"]:visible:checked').length == 0) 
                    e.preventDefault();
                    hasErrors = true;
                    return false;
                
            );
            if (hasErrors) 
                $(".validation-summary-valid").find("ul").append("<li>You must select at least one answer for every question</li>").end().show();
             else 
                $(".validation-summary-errors").find("li:contains('You must select at least one answer for every question'')").remove().end().hide();
            
        );
    );
</script>

@using (html.BeginForm())

    @Html.ValidationSummary(false)
<fieldset>
    <legend></legend>
    <div class="takeAssessment">
    @if(!string.IsNullOrEmpty(ViewBag.AssessmentInstructions)) 
        <h4>Instructions</h4>
        <p>@ViewBag.AssessmentInstructions</p>
    
    @
    int questionCount = 0;
    int totalQuestions = Model.Count();

    @Html.Hidden("ModuleID", (int)ViewBag.ModuleID)
    for (var i = 0; i < Model.Count; i++)
    

        @Html.HiddenFor(m => m[i].questionDescription)
            <div class="newQuestionWrapper">
                    <h4>Question @(i + 1) of @totalQuestions</h4>
                    @Html.HiddenFor(m => m[i].assessmentID)
                    @Html.HiddenFor(m => m[i].assessmentQuestionID)
                    <p class="questionDescription">@Model[i].questionDescription</p>
                    <div class="newAnswerWrapper"></div>

                <div class="newAnswerWrapper">
                    <div class="answerHeader">
                        <p class="correct">Select</p><p class="answers">Answer(s)</p>
                    </div>

                 @for (var j = 0; j < Model[i].assessmentAnswers.Count(); j++)
                 
                    @Html.HiddenFor(m => m[i].assessmentAnswers[j].assessmentAnswerID)
                    @Html.HiddenFor(m => m[i].assessmentAnswers[j].assessmentQuestionID)
                    @Html.HiddenFor(m => m[i].assessmentAnswers[j].assessmentAnswer)

                     if (ViewBag.Status == "questions")
                               
                         <div class="answerRow">
                            <span class="isAnswer first">@Html.CheckBoxFor(m => m[i].assessmentAnswers[j].userAnswer)</span>
                            <span class="answerDisplay">@Html.DisplayFor(m => m[i].assessmentAnswers[j].assessmentAnswer)</span>
                            @Html.HiddenFor(m => m[i].assessmentAnswers[j].isAnswer)
                            <div class="clear"></div>
                         </div>
                     
                     else
                     
                        <div class="answerRow">
                            @
                                string cls = Model[i].assessmentAnswers[j].isAnswer ? "correct" : "incorrect";
                            
                            <span class="isAnswer first">@Html.CheckBoxFor(m => m[i].assessmentAnswers[j].userAnswer, new  @disabled = "disabled" )</span>
                            <span class="answerDisplay" style="width: 510px !important;">@Html.DisplayFor(m => m[i].assessmentAnswers[j].assessmentAnswer)</span>
                            <span class="isAnswer"><span class="@cls">@Html.DisplayFor(m => m[i].assessmentAnswers[j].isAnswer)</span></span>

                            <div class="clear"></div>
                        </div>
                     
                     <div class="clear"></div>
                 

              </div>

    <div class="clear"></div>
            </div>
    


    <div class="clear"></div>
    </div>
    @if (ViewBag.Status == "questions")
    
    <input type="submit" id="submit" value="Submit Assessment" class="redButton197x38" />
    
</fieldset>

<p>
    @Html.ActionLink("Back to Module", "Learn", new  id = ViewBag.ModuleID , new  @class = "redButton197x38" )
</p>

【问题讨论】:

您可以在这里添加您的视图信息吗? 在此期间,您说您正在通过 jQuery 删除重复项 - 您也可以在 ModelState 对象的控制器中执行此操作 现在测试你的答案。 【参考方案1】:

我一直在考虑你的问题,我认为这个问题比我想的要简单得多,ValidationResult 类有一个重载的构造函数,它要求传入成员名称,如果你传入相同的键( new List() "QuestionError" ) ) 在这里它应该将它们分组并只显示一个结果。

【讨论】:

以上是关于在 MVC3 中处理验证 - 每个复选框组必须选择一个复选框的主要内容,如果未能解决你的问题,请参考以下文章

html 只选择一个组中的一个复选框

如何验证单选按钮/复选框并且必须在 laravel 中选择一个

Angular2中的复选框组处理和验证

至少一个复选框必须在其中一个取消选择操作时保持选中状态

在进入系统之前必须输入两次登录凭据 - MVC3

MVC3 输入相关验证