Search code examples
javascriptjqueryasp.net-mvc-4checkboxrequiredfieldvalidator

MVC4 Jquery validate checkbox to check at least one?


i'm implementing a checkbox question for let user to choose. However, if admin set the question mandatory to true, the checkbox must select at least 1 to submit, else a message will prompt user to select. Tried the jquery but when click button, nothing happen.

Any mistakes that ive done?

My View:

    @model List<IFXSurveyTool.Models.AnswerQuestionViewModel>

    <script>

            var messageContainer = $('.errormessage');

            $('#save').click(function () {
                // Get all mandatory containers
                var mandatory = $('.mandatory');
                $.each(mandatory, function () {
                    var numChecked = $(this).find('input:checked').length;
                    if (numChecked === 0) {
                        messageContainer.text('At least one checkbox must be selected.');
                        return false;
                    }
                });
            });

            $('.mandatory').on('click', 'input[type="checkbox"]', function () {
                messageContainer.text('');
            });


    </script>

    <br />
    <h2>Questions</h2>
    <br />

    @using (Html.BeginForm())
    {
        <div class="errormessage"></div>
           <div class="checkboxcontainer mandatory">
              @for (int x = 0; x < Model[i].Choice_SubQuestion.Count(); x++)
                  {


                           <input type="checkbox" name="[@i].MultiAnswer[@x]" value="@Model[i].Choice_SubQuestion[x]" />
                           @Html.HiddenFor(m => m[i].MultiAnswer[x])
                           @Html.LabelFor(m => m[i].MultiAnswer[x], Model[i].Choice_SubQuestion[x].ToString(), new { @class = "questionlist1" })



         }
  </div>

    <button type="button" id="save">Save</button> 
}

After generating the checkbox in HTML:

<div class="checkboxcontainer mandatory">
<input type="checkbox" name="[0].MultiAnswer[0]" value="1">
<input name="[0].MultiAnswer[0]" type="hidden" value="">
<label class="questionlist1" for="">1</label>
<input type="checkbox" name="[0].MultiAnswer[1]" value="2">
<input name="[0].MultiAnswer[1]" type="hidden" value="">
<label class="questionlist1" for="">2</label>
<input type="checkbox" name="[0].MultiAnswer[2]" value="3">
<input name="[0].MultiAnswer[2]" type="hidden" value="">
<label class="questionlist1" for="">3</label>
</div>

Solution

  • Firstly, your giving all the containing <div> elements class="mandatory" and only ever generating checkboxes if Model[i].Mandatory is true so you html should be

    for (int x = 0; x < Model[i].Choice_SubQuestion.Count; x++)
    {
      @{var attributes = Model[i].Mandatory ? "checkboxgroup mandatory" : "checkboxgroup";}
      <div class="@attributes">
        <div class="message></div>
        <input type="checkbox" name="[@i].MultiAnswer[@x]" value="@Model[i].Choice_SubQuestion[x]" />
        @Html.HiddenFor(m => m[i].MultiAnswer[x])
        @Html.LabelFor(m => m[i].MultiAnswer[x], Model[i].Choice_SubQuestion[x].ToString(), new { @class = "questionlist1" })
      </div>
    }
    <input value="Submit" type="submit" class="btn" id="save" />
    

    Next, your button is a submit button so the form is actually submitting (before the error message has a chance to become visible). Change the scripts to

    $('#save').click(function() {
      var canSubmit = true;
      // Get all mandatory containers
      var mandatory = $('.mandatory');
      $.each(mandatory, function() {
        var numChecked = $(this).find('input:checked').length;
        if (numChecked === 0) {
          canSubmit = false; // signal we can't submit
          // display error message;
          $(this).children('.message').text('At least one checkbox must be selected');
    
          return false; // exit the loop
        }
      });
      if (!canSubmit) {
        return false; // cancel the default submit
      }
    });
    
    $('.mandatory').on('click', 'input[type="checkbox"]', function() {
      $(this).closest('.mandatory').children('.message').text(''); // clear any existing error message
    });
    

    Note also the scripts must be at the bottom of the page (immediately before the closing </body> tag) or wrapped in $(document).ready() { ..... } or $(function() { ..... }); (shorthand version).