What are MVC Validation Extensions?
MVC Validation Extensions is a library that builds upon ASP.NET MVC by providing additional validation attributes to use.
Features
- Familiar usage by extending ASP.NET MVC data annotations
- Client and server validation methods
- Dynamic comparison of dates or numeric fields
- Model attributes
Getting Started
To get started with the additional attributes just install the MVCValidationExtensions nuget package into your solution. Add the appropriate attributes to your models.
Additional Implemented Attributes
- Comparison – Validates that the property meets the comparison with the specified other property
- GreaterThan
- GreaterThanEqualTo
- LessThan
- LessThanEqualTo
- RequiredIf – Causes the property to be required if the specified other property is not null
- RequiredIfValue – Causes the property to be required if the specified other property is equal to the specified other value
- RequiredIfAnyValue – Causes the property to be required if the specified other property is equal to any of the specified other values
- RequiredIfEmpty – Causes the property to be required if the specified other property is empty (whitespace is considered empty)
Usage
Using the MVC Validation Extensions is simple because they are used the same way the current validation attributes are.
Given the following Model…
public class TestModel { [RequiredIf("RequiredIntControl")] public int? SomeIntThatMightBeRequired { get; set; } [RequiredIfValue("RequiredIntControl", "15")] public int? SomeRequiredIfValue { get; set; } public string RequiredIntControl { get; set; } [RequiredIfAnyValue("RequiredIfAnyValueControl", new []{"ValOne", "ValTwo", "ValThree"})] public int? RequiredIfAnyValue { get; set; } public string RequiredIfAnyValueControl { get; set; } [DisplayName("> Hidden Int")] [GreaterThan("HiddentInt")] public int? SomeValue { get; set; } [Required] [GreaterThan("SomeValue", ErrorMessage = "Overriding the error message.")] public int? RequiredInt { get; set; } [Required] [DisplayName("< Date")] [LessThan("SomeOtherDate")] public DateTime? SomeDate { get; set; } [DisplayName("<= Some Other Date")] [LessThanEqualTo("HiddenDateTime")] public DateTime? SomeOtherDate { get; set; } [DisplayName(">= Kendo Date")] [GreaterThanEqualTo("KendoDateOther")] public DateTime? KendoDate { get; set; } public int? HiddentInt { get; set; } public DateTime? HiddenDateTime { get; set; } public DateTime? KendoDateOther { get; set; } }
We get the following results…
how to do group validation?
Kam,
Can you be more specific as to the scenario that you are having trouble validating?
I am using your MVC validation extensions within a modal that is loaded via ajax and showing/hiding controls based on selections. Since the form is reloading, in order for the unobtrusive validation to occur I had to manually call the unobtrusive jquery validation:
$(document).on(‘click’, ‘#btnSave’, function () {
$.validator.unobtrusive.parse(“#preceptorform”);
});
but this doesnt seem to work with your mvcvalidationextensions.unobtrusive.js functionality since the validator works on first load, then stops working the second time. Is there a way that I can call your checks within the button click of the modal?
Stephen,
This is what I typically do after loading in a new form via Ajax:
var form = $(‘form’);
form.removeData(‘validator’);
form.removeData(‘unobtrusiveValidation’);
$.validator.unobtrusive.parse(form);
This will parse the entire form which I have not had any issues with. If you still have issues are you able to setup a jsfiddle or jsbin and I can help you take a closer look?
thank you! This worked!
Does this work with Html.EditorFor in Razor Forms:
Here is my Model:
[DisplayName(“Start Date”)]
[Required(ErrorMessage=”A Start Date is Required”)]
public DateTime? StartDate
{
get; set;
}
[DisplayName(“End Date”)]
[Required(ErrorMessage = “An End Date is Required”)]
[GreaterThanEqualTo(“StartDate”, ErrorMessage =”End Date Must be later than the StartDate”)]
public DateTime? EndDate
{
get; set;
}
Here is my CSHTML:
@Html.ValidationSummary(true, “”, new
{
@class = “text-danger”
})
@Html.LabelFor(m => m.StartDate, new
{
@class = “col-md-3 control-label”
})
@Html.EditorFor(m => m.StartDate)
@Html.ValidationMessageFor(m => m.StartDate, “”, new
{
@class = “text-danger”
})
@Html.LabelFor(m => m.EndDate, new
{
@class = “col-md-3 control-label”
})
@Html.EditorFor(m => m.EndDate)
@Html.ValidationMessageFor(m => m.EndDate, “”, new
{
@class = “text-danger”
})
I don’t get any validation message if I put a start date > the end date.
I have jquery.validate.unobstrusive loaded with my bundles. I get an error if I don’t enter anything in the date fields.
I figured out the issue. I didn’t have the script loaded in my bundle. Not sure if I ever saw that in the installation instructions.
What is the best method to use for determine if the checkbox is true. We are try RequiredIFValue(); but I doesn’t seem to work
You can use the RequiredIf attribute for checkboxes. If you are setting different values on checkboxes other than default True/False you’d want to use RequiredIfValue.
I have used RequiredIFValue in bool? property. and seems like it is not working. can you suggest way how to apply RequiredIFValue in bool? property.
Is there any way you can post your model and view code to Github perhaps?
How can we use same attribute multiple times on same property?
For example :-
RequiredIf(someproperty1,1)
RequiredIf(someproperty2,2)
RequiredIf(someproperty3,3)
public string property {get; set;}
Unfortunately it will not work like this. This would require a new extension.
How can you skip form validation for those html elements that are hidden? I have two elements, Min and Max that get validated even if they are hidden which makes my form put out an error.
This is actually probably a better question for jQuery validate, however, the default settings of jQuery validate are set to ignore hidden fields so anything hidden should not be causing validation.
They best I can do without seeing your full model and view code is that you can override or reconfigure jQuery validate with something like the following:
var inputForm = $(‘form’);
if ($.data(inputForm[0], ‘validator’)) {
$.data(inputForm[0], ‘validator’).settings.ignore = ‘:hidden’;
}
Where ‘:hidden’ is a selector as to the elements that you want ignored.
Hi Nick!
I have a viewmodel like this:
Public Class nomination
{
[DataType(DataType.Upload)]
[Required(ErrorMessage =”You must upload a letter.”)]
[FileType(“doc,docx,pdf,DOC,DOCX,PDF”, ErrorMessage =”Must upload DOC, DOCX, or PDF file.”)]
public HttpPostedFileBase FileUpload { get; set; }
[Required]
public List committees { get; set; } = Helpers.helpers.getCommittees();
}
public class committeeVM
{
public int commid { get; set; }
public string commname { get; set; }
public bool isselected { get; set; }
}
TheCommitteeVM is the results of a checkbox list (isselected is true if one is selected…)
I am needing to require the file upload IF one of the nominations.Committees.isselected = true and the nominations.Committees.commid is a specific value, say 2 or 3.
Is there a way to use the extensions to accomplish this when the property is part of a list object within the viewmodel?
Unfortunately the validation extensions won’t be able to pull from a collection so this is something that you will need to check manually.
Nick, I downloaded your extension into my project and I’m trying to trigger the validation in a Modal window. Regular data annotations will display ok, but the ones from your extension break the modal and refresh the page and display without styles.
MODEL LOOKS LIKE THIS:
public int ContactID { get; set; }
[Required]
[DisplayName(“Category”)]
public int CategoryID { get; set; }
[Required]
[DisplayName(“Level”)]
public int LevelTypeID { get; set; }
[RequiredIfValue(“CategoryID”, “1”)]
[DisplayName(“First Name”)]
public string FirstName { get; set; }
[RequiredIfValue(“CategoryID”, “1”)]
[DisplayName(“Last Name”)]
public string LastName { get; set; }
[RequiredIfValue(“CategoryID”, “2”)]
public string Company { get; set; }
____________________________________________
PARTIAL VIEW LOOKS LIKE THIS:
@model AutomationPro.Contact
@*http://~/Scripts/jquery.validate.unobtrusive.min.js*@
$(“#firstname1”).hide();
$(“#firstname2”).hide();
$(“#firstname3”).hide();
$(“#lastname1”).hide();
$(“#lastname2”).hide();
$(“#lastname3”).hide();
$(“#company1”).hide();
$(“#company2”).hide();
$(“#company3”).hide();
$(document).ready(function () {
$(‘#category’).on(‘change’, function () {
if (this.value == ‘1’)
{
$(“#firstname1”).show();
$(“#firstname2”).show();
$(“#firstname3”).show();
$(“#lastname1”).show();
$(“#lastname2”).show();
$(“#lastname3”).show();
$(“#company1”).hide();
$(“#company2”).hide();
$(“#company3”).hide();
}
else {
$(“#firstname1”).hide();
$(“#firstname2”).hide();
$(“#firstname3”).hide();
$(“#lastname1”).hide();
$(“#lastname2”).hide();
$(“#lastname3”).hide();
$(“#company1”).show();
$(“#company2”).show();
$(“#company3”).show();
}
});
});
×
Contact
@using (Html.BeginForm(null, null, FormMethod.Post, new { @enctype = “multipart/form-data”, id = “createContactchoice” }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true, “”, new { @class = “text-danger” })
@Html.HiddenFor(model => model.ContactID)
@Html.HiddenFor(model => model.LevelTypeID)
Category
@Html.DropDownList(“CategoryID”, ViewBag.Categories as SelectList, String.Empty, new { @class = “form-control”, id = “category” })
@Html.ValidationMessageFor(model => model.CategoryID, “”, new { @class = “text-danger” })
@Html.EditorFor(model => model.ContactTypes)
First Name
@Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = “form-control” } })
@Html.ValidationMessageFor(model => model.FirstName, “”, new { @class = “text-danger” })
Last Name
@Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = “form-control” } })
@Html.ValidationMessageFor(model => model.LastName, “”, new { @class = “text-danger” })
Company
@Html.EditorFor(model => model.Company, new { htmlAttributes = new { @class = “form-control” } })
@Html.ValidationMessageFor(model => model.Company, “”, new { @class = “text-danger” })
Cancel
}
I’m assuming the partial view is the one that is loaded into the modal. There shouldn’t be any issues with the extensions in a modal or a popup. Can you open your dev tools and check to see if you have any javascript errors in the console when the modal opens up or when the validation should be firing?
I just added version 1.1.4.0 to my site. Server side validation is working but the client side validation isn’t. are there any additional steps I need to take to get the client side to work as expected?
Sorry you can ignore this…. totally didn’t see the “/mvcvalidationextensions.unobtrusive.js” in my project. Sorry.
Any plans to make these great validators for .net Core?
Yes I would like to do this eventually but I don’t really have a timetable at the moment.
Do you need to do something different to get the validation to work when the field is part of a collection? I had it working and then the client asked to be able to add multiples of a particular item, so I am dynamically adding a chunk of HTML VIA ajax, I am doing the whole:
var form = $(‘form’);
form.removeData(‘validator’);
form.removeData(‘unobtrusiveValidation’);
$.validator.unobtrusive.parse(form);
thing after my HTML has been loaded. And all of the other validations are working (my regex format validation and such), but not the RequiredIf. I am just wondering if it is going to be able to find the property now that it has been prefixed…..
[RequiredIf(“MyProperty”)]
… the field that needs to be required if MyProperty is set …
I am rendering out the multiples inside a
Html.BeginCollectionItem(“MyProperties”)
block so they are rendering out with IDs like:
MyProperties_fd6f09cc-1646-42f4-84e0-7c4a79df9ab0__MyProperty
The field’s HTML looks like:
data-val-requiredif-otherproperty=”MyProperty”
but I am linking it should be:
data-val-requiredif-otherproperty=”MyProperties_fd6f09cc-1646-42f4-84e0-7c4a79df9ab0__MyProperty”
Am I missing something?
Thanks
If I mess around with the HTML in chrome dev tools. If I set the attribute to:
data-val-requiredif-otherproperty=”MyProperties[fd6f09cc-1646-42f4-84e0-7c4a79df9ab0]MyProperty”
And do the reparse form validation stuff then it works. Looks like the field prefix isn’t being respected as part of the attribute creation.
You’re correct. Ya unfortunately it isn’t designed to work with a collection like that. The javascript would need to know the exact name that it needs to depend on. I haven’t really looked into this before so I’m not quite sure it is possible or not (I imagine it is) but just not supported right now.