Skip to content

Instantly share code, notes, and snippets.

@johnnyreilly
Last active June 18, 2018 13:58
Show Gist options
  • Save johnnyreilly/5867188 to your computer and use it in GitHub Desktop.
Save johnnyreilly/5867188 to your computer and use it in GitHub Desktop.
jQuery Validate - using the native unobtrusive support
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<style>
form { padding: 10px; }
.error { color: red; }
</style>
</head>
<body>
<form>
<label for="RequiredDateDemo">A date is required (eg "15 June 2012"):</label>
<input
data-msg-date="The field RequiredDateDemo must be a date."
data-msg-required="The RequiredDateDemo field is required."
data-rule-date="true"
data-rule-required="true"
id="RequiredDateDemo" name="RequiredDateDemo" type="text" value="" />
<hr />
<label for="StringLengthAndRequiredDemo">A string is required between 5 and 10 characters long:</label>
<input
data-msg-maxlength="The field StringLengthAndRequiredDemo must be a string with a minimum length of 5 and a maximum length of 10."
data-msg-minlength="The field StringLengthAndRequiredDemo must be a string with a minimum length of 5 and a maximum length of 10."
data-msg-required="The StringLengthAndRequiredDemo field is required."
data-rule-maxlength="10"
data-rule-minlength="5"
data-rule-required="true"
id="StringLengthAndRequiredDemo" name="StringLengthAndRequiredDemo" type="text" value="" />
<hr />
<label for="RangeAndNumberDemo">Must be a number between -20 and 40:</label>
<input
data-msg-number="The field RangeAndNumberDemo must be a number."
data-msg-range="The field RangeAndNumberDemo must be between -20 and 40."
data-rule-number="true"
data-rule-range="[-20,40]"
id="RangeAndNumberDemo" name="RangeAndNumberDemo" type="text" value="-21" />
<hr />
<label for="RangeAndNumberDemo">An option must be selected:</label>
<select
data-msg-required="The DropDownRequiredDemo field is required."
data-rule-required="true"
id="DropDownRequiredDemo" name="DropDownRequiredDemo">
<option value="">Please select</option>
<option value="An Option">An Option</option>
</select>
<hr />
<button type="submit">Validate</button>
</form>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery.validate/1.11.1/jquery.validate.js" type="text/javascript"></script>
<script type="text/javascript">
var $form = $("form");
$form.validate();
$form.submit(function (event) {
if ($form.validate().valid()) {
event.preventDefault();
alert("Valid!");
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<style>
form { padding: 10px; }
.error { border: 1px solid #b94a48!important; background-color: #fee!important; }
</style>
</head>
<body>
<form>
<div class="row">
<label for="RequiredDateDemo">A date is required (eg "15 June 2012"):</label>
<input
data-msg-date="The field RequiredDateDemo must be a date."
data-msg-required="The RequiredDateDemo field is required."
data-rule-date="true"
data-rule-required="true"
id="RequiredDateDemo" name="RequiredDateDemo" type="text" value="" />
</div>
<div class="row">
<label for="StringLengthAndRequiredDemo">A string is required between 5 and 10 characters long:</label>
<input
data-msg-maxlength="The field StringLengthAndRequiredDemo must be a string with a minimum length of 5 and a maximum length of 10."
data-msg-minlength="The field StringLengthAndRequiredDemo must be a string with a minimum length of 5 and a maximum length of 10."
data-msg-required="The StringLengthAndRequiredDemo field is required."
data-rule-maxlength="10"
data-rule-minlength="5"
data-rule-required="true"
id="StringLengthAndRequiredDemo" name="StringLengthAndRequiredDemo" type="text" value="" />
</div>
<div class="row">
<label for="RangeAndNumberDemo">Must be a number between -20 and 40:</label>
<input
data-msg-number="The field RangeAndNumberDemo must be a number."
data-msg-range="The field RangeAndNumberDemo must be between -20 and 40."
data-rule-number="true"
data-rule-range="[-20,40]"
id="RangeAndNumberDemo" name="RangeAndNumberDemo" type="text" value="-21" />
</div>
<div class="row">
<label for="RangeAndNumberDemo">An option must be selected:</label>
<select
data-msg-required="The DropDownRequiredDemo field is required."
data-rule-required="true"
id="DropDownRequiredDemo" name="DropDownRequiredDemo">
<option value="">Please select</option>
<option value="An Option">An Option</option>
</select>
</div>
<div class="row">
<button type="submit">Validate</button>
</div>
</form>
<script src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.9.1.js" type="text/javascript"></script>
<script src="//ajax.aspnetcdn.com/ajax/jQuery.validate/1.11.1/jquery.validate.js" type="text/javascript"></script>
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script type="text/javascript">
$("form").validate({
showErrors: function(errorMap, errorList) {
// Clean up any tooltips for valid elements
$.each(this.validElements(), function (index, element) {
var $element = $(element);
$element.data("title", "") // Clear the title - there is no error associated anymore
.removeClass("error")
.tooltip("destroy");
});
// Create new tooltips for invalid elements
$.each(errorList, function (index, error) {
var $element = $(error.element);
$element.tooltip("destroy") // Destroy any pre-existing tooltip so we can repopulate with new tooltip content
.data("title", error.message)
.addClass("error")
.tooltip(); // Create a new tooltip based on the error messsage we just set in the title
});
},
submitHandler: function(form) {
alert("This is a valid form!");
}
});
</script>
</body>
</html>
@model MyMvcApp.Models.MyViewModel
@using (Html.BeginForm())
{
@Html.TextBoxFor(x => x.DateTimeDemo, true)
<hr />
@Html.TextBoxFor(x => x.StringLengthAndRequiredDemo, true)
<hr />
@Html.TextBoxFor(x => x.RangeAndNumberDemo, true)
<hr />
@Html.DropDownListFor(x => x.DropDownRequiredDemo, true, new SelectList(new List<SelectListItem>()))
<button type="submit">Validate</button>
}
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc.Html;
using System.Web.Routing;
namespace System.Web.Mvc
{
/// <summary>
/// MVC HtmlHelper extension methods - extensions that make use of jQuery Validates native unobtrusive data validation properties
/// </summary>
public static class jQueryValidateRawUnobtrusiveExtensions
{
private const string data_val_required = "data-val-required";
private const string data_val_number = "data-val-number";
private const string data_val_date = "data-val-date";
private const string data_val_length = "data-val-length";
private const string data_val_length_min = "data-val-length-min";
private const string data_val_length_max = "data-val-length-max";
private const string data_val_range = "data-val-range";
#region Public
/// <summary>
/// Render a TextBox for the supplied model using native jQuery Validate Unobtrusive extensions (only if true passed)
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="htmlHelper"></param>
/// <param name="expression"></param>
/// <param name="useRawUnobtrusiveAttributes">Pass true if you want to use native extensions</param>
/// <param name="htmlAttributes">OPTIONAL</param>
/// <returns></returns>
public static IHtmlString TextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
bool useRawUnobtrusiveAttributes,
object htmlAttributes = null)
{
// Return to native if true not passed
if (!useRawUnobtrusiveAttributes)
return htmlHelper.TextBoxFor(expression, htmlAttributes);
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var attributes = GetUnobtrusiveValidationAttributes(htmlHelper, expression, htmlAttributes, metadata);
return htmlHelper.TextBox(metadata.PropertyName, metadata.Model, attributes);
}
/// <summary>
/// Render a DropDownList for the supplied model using native jQuery Validate Unobtrusive extensions (only if true passed)
/// </summary>
/// <typeparam name="TModel"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="htmlHelper"></param>
/// <param name="expression"></param>
/// <param name="useRawUnobtrusiveAttributes"></param>
/// <param name="selectList"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString DropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
bool useRawUnobtrusiveAttributes,
IEnumerable<SelectListItem> selectList,
object htmlAttributes = null)
{
// Return to native if true not passed
if (!useRawUnobtrusiveAttributes)
return htmlHelper.DropDownListFor(expression, selectList, htmlAttributes);
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var attributes = GetUnobtrusiveValidationAttributes(htmlHelper, expression, htmlAttributes, metadata);
return htmlHelper.DropDownList(metadata.PropertyName, selectList, attributes);
}
private static RouteValueDictionary GetUnobtrusiveValidationAttributes<TModel, TProperty>(HtmlHelper<TModel> helper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes,
ModelMetadata metadata)
{
var propertyName = helper.NameFor(expression).ToString();
var unobtrusiveValidationAttributes = helper.GetUnobtrusiveValidationAttributes(propertyName, metadata);
var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
// Required
if (unobtrusiveValidationAttributes.ContainsKey(data_val_required))
{
attributes.Add("data-rule-required", "true");
attributes.Add("data-msg-required", unobtrusiveValidationAttributes[data_val_required]);
}
// Number
if (unobtrusiveValidationAttributes.ContainsKey(data_val_number))
{
attributes.Add("data-rule-number", "true");
attributes.Add("data-msg-number", unobtrusiveValidationAttributes[data_val_number]);
}
// Date
if (unobtrusiveValidationAttributes.ContainsKey(data_val_date))
{
attributes.Add("data-rule-date", "true");
attributes.Add("data-msg-date", unobtrusiveValidationAttributes[data_val_date]);
}
// Min and Max Length
if (unobtrusiveValidationAttributes.ContainsKey(data_val_length))
{
if (unobtrusiveValidationAttributes.ContainsKey(data_val_length_min))
{
attributes.Add("data-rule-minlength", unobtrusiveValidationAttributes[data_val_length_min]);
attributes.Add("data-msg-minlength", unobtrusiveValidationAttributes[data_val_length]);
}
if (unobtrusiveValidationAttributes.ContainsKey(data_val_length_max))
{
attributes.Add("data-rule-maxlength", unobtrusiveValidationAttributes[data_val_length_max]);
attributes.Add("data-msg-maxlength", unobtrusiveValidationAttributes[data_val_length]);
}
}
// Range
if (unobtrusiveValidationAttributes.ContainsKey(data_val_range))
{
attributes.Add("data-rule-range",
string.Format("[{0},{1}]", unobtrusiveValidationAttributes["data-val-range-min"],
unobtrusiveValidationAttributes["data-val-range-max"])
);
attributes.Add("data-msg-range", unobtrusiveValidationAttributes[data_val_range]);
}
return attributes;
}
#endregion
}
}
using System.Web.Mvc;
using MyMvcApp.Models;
namespace MyMvcApp.Controllers
{
public class MyController : System.Web.Mvc.Controller
{
public MyController()
{
}
[HttpGet]
public ViewResult Index()
{
return View(new MyViewModel());
}
}
}
using System.ComponentModel.DataAnnotations;
namespace MyMvcApp.Models
{
public class MyViewModel
{
public System.DateTime DateTimeDemo { get; set; }
[StringLength(10, MinimumLength = 5),
Required]
public string StringLengthAndRequiredDemo { get; set; }
[Range(typeof(decimal), "-100.5", "99.5")]
public decimal? RangeAndNumberDemo { get; set; }
[Required]
public string DropDownRequiredDemo { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment