Adding an appropriate sample to use ValidationMessage and ValidationMessageFor.

This commit is contained in:
sornaks 2014-04-15 15:59:56 -07:00
parent f17d444b8a
commit 185ad31491
8 changed files with 170 additions and 95 deletions

View File

@ -8,6 +8,7 @@ namespace MvcSample.Web.Models
[MinLength(4)]
public string Name { get; set; }
public string Address { get; set; }
[Range(27, 70)]
public int Age { get; set; }
public decimal GPA { get; set; }
public User Dependent { get; set; }

View File

@ -50,6 +50,9 @@
<td>
@Html.TextBox("Name")
</td>
<td>
@Html.ValidationMessage("Name.Name", "Name is required", new { @style = "font-weight: bold" })
</td>
</tr>
<tr>
<td>
@ -66,6 +69,9 @@
<td>
@Html.DropDownListFor(model => model.Age, (IEnumerable<SelectListItem>)ViewBag.Ages, htmlAttributes: new { @class = "form-control" })
</td>
<td>
@Html.ValidationMessageFor(model => model.Age, "Age must be between 27 and 70", new { @style = "font-weight: bold" })
</td>
</tr>
<tr>
<td>

View File

@ -416,6 +416,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
return new HtmlString(value == null ? null : value.ToString());
}
/// <inheritdoc />
public HtmlString ValidationMessage(string expression, string message, object htmlAttributes)
{
return GenerateValidationMessage(expression, message, htmlAttributes);
}
/// <inheritdoc />
public virtual HtmlString ValidationSummary(bool excludePropertyErrors, string message, IDictionary<string, object> htmlAttributes)
{
@ -508,46 +514,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
return divBuilder.ToHtmlString(TagRenderMode.Normal);
}
public HtmlString ValidationMessage(string name, string message, object htmlAttributes)
{
ModelState modelState;
ViewData.ModelState.TryGetValue(name, out modelState);
ModelErrorCollection errors = null;
if (modelState != null)
{
errors = modelState.Errors;
}
bool hasError = errors != null && errors.Any();
if (!hasError && !ViewContext.UnobtrusiveJavaScriptEnabled)
{
return null;
}
else
{
string error = null;
if (hasError)
{
error = message ?? errors.First().ErrorMessage;
}
var tagBuilder = new TagBuilder("span") { InnerHtml = Encode(error) };
tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes));
if (ViewContext.UnobtrusiveJavaScriptEnabled)
{
bool replaceValidationMessageContents = string.IsNullOrEmpty(message);
tagBuilder.MergeAttribute("data-valmsg-for", name);
tagBuilder.MergeAttribute("data-valmsg-replace",
replaceValidationMessageContents.ToString().ToLowerInvariant());
}
tagBuilder.AddCssClass(hasError ? ValidationMessageCssClassName : ValidationMessageValidCssClassName);
return tagBuilder.ToHtmlString(TagRenderMode.Normal);
}
}
/// <summary>
/// Returns the HTTP method that handles form input (GET or POST) as a string.
/// </summary>
@ -698,7 +664,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var resolvedDisplayName = metadata.PropertyName;
if (resolvedDisplayName == null)
{
resolvedDisplayName = string.IsNullOrEmpty(htmlFieldName) ?
resolvedDisplayName = string.IsNullOrEmpty(htmlFieldName) ?
string.Empty :
htmlFieldName.Split('.').Last();
}
@ -823,7 +789,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
return new HtmlString(Encode(ViewData.TemplateInfo.GetFullHtmlFieldName(expression)));
}
protected virtual HtmlString GenerateLabel([NotNull] ModelMetadata metadata,
protected virtual HtmlString GenerateLabel([NotNull] ModelMetadata metadata,
string htmlFieldName,
string labelText,
object htmlAttributes)
@ -832,7 +798,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
string resolvedLabelText = labelText ?? metadata.PropertyName;
if (resolvedLabelText == null)
{
resolvedLabelText = string.IsNullOrEmpty(htmlFieldName) ?
resolvedLabelText = string.IsNullOrEmpty(htmlFieldName) ?
string.Empty :
htmlFieldName.Split('.').Last();
}
@ -1220,6 +1186,76 @@ namespace Microsoft.AspNet.Mvc.Rendering
return tagBuilder.ToHtmlString(TagRenderMode.SelfClosing);
}
protected virtual HtmlString GenerateValidationMessage(string expression, string message,
object htmlAttributes)
{
var modelName = ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
if (string.IsNullOrEmpty(modelName))
{
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "expression");
}
var formContext = ViewContext.GetFormContextForClientValidation();
if (!ViewData.ModelState.ContainsKey(modelName) && formContext == null)
{
return null;
}
ModelState modelState;
var tryGetModelStateResult = ViewData.ModelState.TryGetValue(modelName, out modelState);
var modelErrors = tryGetModelStateResult ? modelState.Errors : null;
ModelError modelError = null;
if(modelErrors != null && modelErrors.Count != 0)
{
modelError = modelErrors.FirstOrDefault(m => !string.IsNullOrEmpty(m.ErrorMessage)) ?? modelErrors[0];
}
if (modelError == null && formContext == null)
{
return null;
}
// Even if there are no model errors, we generate the span and add the validation message
// if formContext is not null.
var builder = new TagBuilder("span");
builder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes));
// Only the style of the span is changed according to the errors if message is null or empty.
// Otherwise the content and style is handled by the client-side validation.
builder.AddCssClass((modelError != null) ?
ValidationMessageCssClassName :
ValidationMessageValidCssClassName);
if (!string.IsNullOrEmpty(message))
{
builder.SetInnerText(message);
}
else if (modelError != null)
{
builder.SetInnerText(ValidationHelpers.GetUserErrorMessageOrDefault(modelError, modelState));
}
if (formContext != null)
{
var replaceValidationMessageContents = string.IsNullOrEmpty(message);
if (ViewContext.UnobtrusiveJavaScriptEnabled)
{
builder.MergeAttribute("data-valmsg-for", modelName);
builder.MergeAttribute("data-valmsg-replace",
replaceValidationMessageContents.ToString().ToLowerInvariant());
}
// TODO: (WebFX-217) Add support for Unobtrusive JS disabled -
// Modify the field metadata to add the validation message,
// Add the client validation id in the field metadata
}
return builder.ToHtmlString(TagRenderMode.Normal);
}
protected virtual HtmlString GenerateValue(string name, object value, string format, bool useViewData)
{
var fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name);

View File

@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// Initializes a new instance of the <see cref="HtmlHelper{TModel}"/> class.
/// </summary>
public HtmlHelper(
[NotNull] IViewEngine viewEngine,
[NotNull] IViewEngine viewEngine,
[NotNull] IModelMetadataProvider metadataProvider,
[NotNull] IUrlHelper urlHelper,
[NotNull] AntiForgery antiForgeryInstance)
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <inheritdoc />
public new ViewDataDictionary<TModel> ViewData { get; private set;}
public new ViewDataDictionary<TModel> ViewData { get; private set; }
public override void Contextualize([NotNull] ViewContext viewContext)
{
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
throw new ArgumentException(Resources.FormatPropertyOfTypeCannotBeNull(
"ViewData",
typeof(ViewContext)),
typeof(ViewContext)),
"viewContext");
}
@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object additionalViewData)
{
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression,
ViewData,
ViewData,
MetadataProvider);
return GenerateDisplay(metadata,
@ -212,7 +212,14 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <inheritdoc />
public HtmlString ValueFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, string format)
public HtmlString ValidationMessageFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
string message, object htmlAttributes)
{
return GenerateValidationMessage(ExpressionHelper.GetExpressionText(expression), message, htmlAttributes);
}
/// <inheritdoc />
public HtmlString ValueFor<TProperty>(Expression<Func<TModel, TProperty>> expression, string format)
{
var metadata = GetModelMetadata(expression);
return GenerateValue(ExpressionHelper.GetExpressionText(expression), metadata.Model, format,

View File

@ -1,9 +1,53 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class HtmlHelperValidationExtensions
{
public static HtmlString ValidationMessage([NotNull] this IHtmlHelper htmlHelper,
string expression)
{
return htmlHelper.ValidationMessage(expression, message: null, htmlAttributes: null);
}
public static HtmlString ValidationMessage([NotNull] this IHtmlHelper htmlHelper,
string expression, string message)
{
return htmlHelper.ValidationMessage(expression, message, htmlAttributes: null);
}
public static HtmlString ValidationMessage([NotNull] this IHtmlHelper htmlHelper,
string expression, object htmlAttributes)
{
return htmlHelper.ValidationMessage(expression, message: null, htmlAttributes: htmlAttributes);
}
public static HtmlString ValidationMessage([NotNull] this IHtmlHelper htmlHelper,
string expression, string message, object htmlAttributes)
{
return htmlHelper.ValidationMessage(expression, message, htmlAttributes);
}
public static HtmlString ValidationMessageFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression)
{
return htmlHelper.ValidationMessageFor(expression, message: null, htmlAttributes: null);
}
public static HtmlString ValidationMessageFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, string message)
{
return htmlHelper.ValidationMessageFor(expression, message, htmlAttributes: null);
}
public static HtmlString ValidationMessageFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, string message, object htmlAttributes)
{
return htmlHelper.ValidationMessageFor(expression, message, htmlAttributes);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper)
{
return ValidationSummary(htmlHelper, excludePropertyErrors: false);
@ -55,41 +99,5 @@ namespace Microsoft.AspNet.Mvc.Rendering
return htmlHelper.ValidationSummary(excludePropertyErrors: false, message: message,
htmlAttributes: htmlAttributes);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName)
{
return ValidationMessage(htmlHelper, modelName, message: null, htmlAttributes: null);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName, string message)
{
return ValidationMessage(htmlHelper, modelName, message, htmlAttributes: null);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName, object htmlAttributes)
{
return ValidationMessage(htmlHelper, modelName, message: null, htmlAttributes: htmlAttributes);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName, IDictionary<string, object> htmlAttributes)
{
return ValidationMessage(htmlHelper, modelName, message: null, htmlAttributes: htmlAttributes);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName, string message, IDictionary<string, object> htmlAttributes)
{
return htmlHelper.ValidationMessage(modelName, message, htmlAttributes);
}
public static HtmlString ValidationMessage<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper,
string modelName, string message, object htmlAttributes)
{
return htmlHelper.ValidationMessage(modelName, message, htmlAttributes);
}
}
}

View File

@ -393,6 +393,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextBox(string name, object value, string format, IDictionary<string, object> htmlAttributes);
/// <summary>
/// Returns the validation message if an error exists in the <see cref="ModelStateDictionary"/> object.
/// </summary>
/// <param name="modelName">The name of the property that is being validated.</param>
/// <param name="message">The message to be displayed. This will always be visible but client-side
/// validation may update the associated CSS class.</param>
/// <param name="htmlAttributes"> An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>An <see cref="HtmlString"/> that contains the validation message</returns>
HtmlString ValidationMessage(string modelName, string message, object htmlAttributes);
/// <summary>
/// Returns an unordered list (ul element) of validation messages that are in the
/// <see cref="ModelStateDictionary"/> object.

View File

@ -224,14 +224,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
IDictionary<string, object> htmlAttributes);
/// <summary>
/// Returns the validation message if an error exists in the <see cref="ModelStateDictionary"/> object.
/// Returns the validation message for the specified expression
/// </summary>
/// <param name="modelName">The name of the property that is being validated.</param>
/// <param name="message">The message to be displayed if the specified field contains an error.</param>
/// <param name="htmlAttributes">Dictionary that contains the HTML attributes which should
/// be applied on the element</param>
/// <returns></returns>
HtmlString ValidationMessage(string modelName, string message, object htmlAttributes);
/// <param name="expression">An expression, relative to the current model.</param>
/// <param name="message">The message to be displayed. This will always be visible but client-side
/// validation may update the associated CSS class.</param>
/// <param name="htmlAttributes"> An object that contains the HTML attributes to set for the element.
/// Alternatively, an /// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>An <see cref="HtmlString"/> that contains the validation message</returns>
HtmlString ValidationMessageFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
string message, object htmlAttributes);
/// <summary>
/// Returns the model value for the given expression <paramref name="expression"/>.

View File

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNet.Abstractions;
using Microsoft.AspNet.Mvc.Rendering;
namespace Microsoft.AspNet.Mvc
@ -82,5 +79,10 @@ namespace Microsoft.AspNet.Mvc
public ViewDataDictionary ViewData { get; set; }
public TextWriter Writer { get; set; }
public FormContext GetFormContextForClientValidation()
{
return (ClientValidationEnabled) ? FormContext : null;
}
}
}