1

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>
11
  • There is nothing built in to MVC that will do this validation for you. You will need to use jquery/javascript to check if any are checked (and you will also need to check again on the server (which you could do by writing your own validation attribute) Commented Jul 28, 2015 at 2:24
  • First your view does not make sense and should not even bind correctly when you post. You have a checkbox with indexed names and unchecked checkboxes do not post back so if any are unchecked, you have non-consecutive indexers which means binding will fail. Then you give the value attribute of the checkbox @Model[i].Choice_SubQuestion[x] which assuming its not a bool and @Model[i].MultiAnswer[x] is, binding would also fail. You need to show your models and the outer for loop in the view to understand better what your trying to do. Commented Jul 28, 2015 at 2:46
  • As for the script, I suggest wrapping the group of checkboxes inside a div and then if (Model[i].Mandatory == true), give the div a class name (say) <div class="mandatory">. Then you can handle the .submit() event, get all elements with that class name, and use a $.each() function to test of any of its checkboxes are checked. If not, then cancel the submit and display an error. Commented Jul 28, 2015 at 2:54
  • Need a break for a while, but if you can't solve it then I can add an example in a few hours. Commented Jul 28, 2015 at 2:58
  • 2
    If this is verbatim how your view is laid out, you're attempting to bind events to markup that hasn't been rendered yet. Either move the script after the markup, or wrap it all in a ready handler. Commented Jul 28, 2015 at 7:06

1 Answer 1

1

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).

Sign up to request clarification or add additional context in comments.

7 Comments

Side note - look at the checkbox you generating - it does not have an id attribute and the label does not have a for attribute pointing to the checkbox (too long to explain why this happens in your case), but either wrap the checkbox inside the label, or manually add unique id attributes to each checkbox and the for attribute in the checkbox label.
Oops - missed the closing } - see edit to answer - it should output <div class="checkboxgroup mandatory"> or <div class="checkboxgroup"> depending on the value of Model[i].Mandatory
See update for alternative (may or may not need to wrap the var attributes = ... inside @{ ... } depending on other code in your view)
i tried but when i press the submit, it will straight go to controller..looks like it did not detect the jquery. Either i tried for wrap the var attributes inside @{...} or not is same. Any idea? THanks.
Bugger, didn't see your message and went ahead and created this DotNetFiddle for you anyway :). But might be useful anyway - it shows one technique for adding the id attributes and making the labels work. It also shows how you should be using a view model with a (say) bool IsSelected property and binding to it using CheckBoxFor() so that you model will be correctly bound when you post back
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.