How to fix the model to correctly use the MVC Foolproof library?

1.5k views Asked by At

I am trying to use MVC Foolproof library to validate my model and show error message respectively. However I am not applying the Data Annotation correctly so the validation does not works.

My requirement is that I have two checkboxes and atleast one of them needs to be checked before submitting the form. Below is the code for both fields in the model with data annotation,

    [RequiredIfFalse("CheckBox2", ErrorMessage = "Please select atleast one checkbox.")]
    public bool Checkbox1 { get; set; }

    [RequiredIfFalse("Checkbox1", ErrorMessage = "Please select atleast one checkbox.")]
    public bool CheckBox2 { get; set; }

Now when I submit the form without checking any checkbox then form is submitted and no error is displayed. I know there is some logical mistake with the model and the way I am applying the custom validation attribute because if I make first field as int or string and make it required if the CheckBox is checked then validation works fine and validation messages are displayed accordingly on the view. Kindly help me in identifying the logical error in above fields.

3

There are 3 answers

10
Adnan Yaseen On BEST ANSWER

I found that my problem is solved when I modified the Foolproof's Data Annotations as below,

    [RequiredIfNot("CheckBox2", true, ErrorMessage = "Please select atleast one checkbox.")]
    public bool CheckBox1 { get; set; }

    [RequiredIfNot("CheckBox1", true, ErrorMessage = "Please select atleast one checkbox.")]
    public bool CheckBox2 { get; set; }

Through this I am actually checking the value which was not achieved by using RequiredIfFalse which was used to check if value is provided or not and I thought that it is checking that whether field value is false. Thanks to @Stephen Muecke for clarifying it to me.

The only short coming is that when both checkboxes are not checked then the error message is displayed for both controls which I want to be displayed just once. But when any of the checkbox is checked then validation works just fine and no error messages are displayed.

Edit: The duplicate error message is removed if I use ErrorMessage=" " for any of the CheckBox. So the error message will be displayed once if no CheckBox is checked and if any of the CheckBox is checked then no error messages will be displayed.

Edit: Here is the code for view,

            <div class="col-sm-3">
                @Html.CheckBoxFor(m => m.CheckBox1)
                @Html.LabelFor(m => m.CheckBox1)
            </div>

            <div class="col-sm-3">
                @Html.CheckBoxFor(m => m.CheckBox2)
                @Html.LabelFor(m => m.CheckBox2)
            </div>

The code for model is also given and now I have provided the code for view. Nothing else being done on the controller and it works without a hack. The error is being displayed in the Validation Summary automatically. I have also used ValidationFor and it works fine with that too.

7
AudioBubble On

A boolean has only 2 states (true or false) and either one is valid so [RequiredIfFalse] is effectively saying that the value must be either true or false, which it always will be assuming your using @Html.CheckBoxFor(). You cannot use a Foolproof validation attribute for this.

1
Cristian E. On
[Required]
public bool DidWin {get;set;}

[RequiredIfFalse(nameof(DidWin))]
public string ExplainationWhyDidntWin {get;set;}  // Doesn't work

[RequiredIfNot(nameof(DidWin), true)]
public string ExplainationWhyDidntWin2 {get;set;} // Works

In order to fix the issue, find mvcfoolproof.unobtrusive.js and replace the following:

var isBool = function (input) {
    return input === true || input === false || input === "true" || input === "false";
};

with

var isBool = function (input) {
    return input === true || input === false || input.toLowerCase() === "true" || input.toLowerCase() === "false";
};

and

else if (isBool(value1)) {
    if (value1 == "false") value1 = false;
    if (value2 == "false") value2 = false;
    value1 = !!value1;
    value2 = !!value2;
}

with

else if (isBool(value1) && isBool(value2)) {
    if (value1 == "false") value1 = false;
    if (value2.toLowerCase() == "false") value2 = false;
    value1 = !!value1;
    value2 = !!value2;
}