Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Model require true

Is there a way through data annotations to require that a boolean property be set to true?

public class MyAwesomeObj{     public bool ThisMustBeTrue{get;set;} } 
like image 730
Marty Trenouth Avatar asked Jan 18 '11 23:01

Marty Trenouth


2 Answers

I would create a validator for both Server AND Client side. Using MVC and unobtrusive form validation, this can be achieved simply by doing the following:

Firstly, create a class in your project to perform the server side validation like so:

public class EnforceTrueAttribute : ValidationAttribute, IClientValidatable {     public override bool IsValid(object value)     {         if (value == null) return false;         if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");         return (bool)value == true;     }      public override string FormatErrorMessage(string name)     {         return "The " + name + " field must be checked in order to continue.";     }      public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)     {         yield return new ModelClientValidationRule         {             ErrorMessage = String.IsNullOrEmpty(ErrorMessage) ? FormatErrorMessage(metadata.DisplayName) : ErrorMessage,             ValidationType = "enforcetrue"         };     } } 

Following this, annotate the appropriate property in your model:

[EnforceTrue(ErrorMessage=@"Error Message")] public bool ThisMustBeTrue{ get; set; } 

And Finally, enable client side validation by adding the following script to your View:

<script type="text/javascript">     jQuery.validator.addMethod("enforcetrue", function (value, element, param) {         return element.checked;     });     jQuery.validator.unobtrusive.adapters.addBool("enforcetrue"); </script> 

Note: We already created a method GetClientValidationRules which pushes our annotation to the view from our model.

If using resource files to supply the error message for internationalization, remove the FormatErrorMessage call (or just call the base) and tweak the GetClientValidationRules method like so:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {     string errorMessage = String.Empty;     if(String.IsNullOrWhiteSpace(ErrorMessage))     {         // Check if they supplied an error message resource         if(ErrorMessageResourceType != null && !String.IsNullOrWhiteSpace(ErrorMessageResourceName))         {             var resMan = new ResourceManager(ErrorMessageResourceType.FullName, ErrorMessageResourceType.Assembly);             errorMessage = resMan.GetString(ErrorMessageResourceName);         }     }     else     {         errorMessage = ErrorMessage;     }      yield return new ModelClientValidationRule     {         ErrorMessage = errorMessage,         ValidationType = "enforcetrue"     }; } 
like image 63
dazbradbury Avatar answered Oct 18 '22 06:10

dazbradbury


I know this is an older post but wanted to share a simple server side way to do this. You create a public property set to true and compare your bool to that property. If your bool is not checked (by default false) the form will not validate.

public bool isTrue { get { return true; } }  [Required] [Display(Name = "I agree to the terms and conditions")] [Compare("isTrue", ErrorMessage = "Please agree to Terms and Conditions")] public bool AgreeTerms { get; set; } 

Razor code

@Html.CheckBoxFor(m => Model.AgreeTerms, new { id = "AgreeTerms", @checked = "checked" }) <label asp-for="AgreeTerms" class="control-label"></label> <a target="_blank" href="/Terms">Read</a> <br /> @Html.ValidationMessageFor(model => model.AgreeTerms, "", new { @class = "text-danger" }) @Html.HiddenFor(x => Model.isTrue) 
like image 31
fields.cage Avatar answered Oct 18 '22 05:10

fields.cage