来自asp.net webforms模型我习惯使用以<span title="Username is Required">*</span>
形式显示错误的验证器。
我很清楚MVC3验证器是如何开箱即用的,所以请不要再解释验证验证器如何在MVC3中工作,因为我很确定我已经将其固定。我想要完成的是将验证错误消息显示为第一段中显示的span标记的标题。
我已经设法在MVC3中复制了这个,但我不确定我的方式是否遵循最佳实践。我将不胜感激是否有更好的方法来完成同样的事情。如果可以在不修改jquery.validate.unobtrusive.js的情况下完成它将会非常棒。
所以我所做的是:
1)将验证消息设置为“*” 2)在有效时隐藏验证消息 3)添加了一个新属性以确定是否将消息添加为标题 4)在onError中添加了2行标记代码,以检查是否在标题中显示错误消息,如果是,则执行此操作。
[.cshtml] @Html.ValidationMessageFor(m => m.Email, "*", new { data_val_usetitle = "true" })
[.css] .field-validation-valid {display:none;}
.js] function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false,
useTitle = $.parseJSON(container.attr("data-val-usetitle")) !== false; /* New Line */
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
error.removeClass("input-validation-error").appendTo(container);
}
else {
if (useTitle) container.attr("title", error.text()); /* New Line */
error.hide();
}
}
答案 0 :(得分:3)
我认为你所做的是最干净的方式。没有办法修改jquery.validate.unobtrusive.js,因为MVC扩展不遵循旧的asp.net方法即时发出javascript。
我刚刚创建了自己的自定义验证扩展calld ValidationIconFor(),以便显示单个图像,其标题设置为错误消息,并且我使用了上面代码的修改版本。
<强> jquery.validate.unobtrusive.js 强>:
function onError(error, inputElement) { // 'this' is the form element
var container = $(this).find("[data-valmsg-for='" + inputElement[0].name + "']"),
replace = $.parseJSON(container.attr("data-valmsg-replace")) !== false,
useTitle = $.parseJSON(container.attr("data-val-usetitle")) !== false;
container.removeClass("field-validation-valid").addClass("field-validation-error");
error.data("unobtrusiveContainer", container);
if (replace) {
container.empty();
if (useTitle)
container.attr("title", error.text());
else
error.removeClass("input-validation-error").appendTo(container);
}
else {
if (useTitle)
container.attr("title", error.text());
error.hide();
}
}
<强> ValidationExtensions.cs 强>:
public static class ValidationExtensions
{
private static string _resourceClassKey;
public static string ResourceClassKey
{
get
{
return _resourceClassKey ?? String.Empty;
}
set
{
_resourceClassKey = value;
}
}
private static FieldValidationMetadata ApplyFieldValidationMetadata(HtmlHelper htmlHelper, ModelMetadata modelMetadata, string modelName)
{
FormContext formContext = htmlHelper.ViewContext.FormContext;
FieldValidationMetadata fieldMetadata = formContext.GetValidationMetadataForField(modelName, true /* createIfNotFound */);
// write rules to context object
IEnumerable<ModelValidator> validators = ModelValidatorProviders.Providers.GetValidators(modelMetadata, htmlHelper.ViewContext);
foreach (ModelClientValidationRule rule in validators.SelectMany(v => v.GetClientValidationRules()))
{
fieldMetadata.ValidationRules.Add(rule);
}
return fieldMetadata;
}
private static string GetInvalidPropertyValueResource(HttpContextBase httpContext)
{
string resourceValue = null;
if (!String.IsNullOrEmpty(ResourceClassKey) && (httpContext != null))
{
// If the user specified a ResourceClassKey try to load the resource they specified.
// If the class key is invalid, an exception will be thrown.
// If the class key is valid but the resource is not found, it returns null, in which
// case it will fall back to the MVC default error message.
resourceValue = httpContext.GetGlobalResourceObject(ResourceClassKey, "InvalidPropertyValue", CultureInfo.CurrentUICulture) as string;
}
return resourceValue ?? "The value '{0}' is invalid.";
}
private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error, ModelState modelState)
{
if (!String.IsNullOrEmpty(error.ErrorMessage))
{
return error.ErrorMessage;
}
if (modelState == null)
{
return null;
}
string attemptedValue = (modelState.Value != null) ? modelState.Value.AttemptedValue : null;
return String.Format(CultureInfo.CurrentCulture, GetInvalidPropertyValueResource(httpContext), attemptedValue);
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return ValidationIconFor(htmlHelper, expression, null /* validationMessage */, new RouteValueDictionary());
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage)
{
return ValidationIconFor(htmlHelper, expression, validationMessage, new RouteValueDictionary());
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, object htmlAttributes)
{
return ValidationIconFor(htmlHelper, expression, validationMessage, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString ValidationIconFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, string validationMessage, IDictionary<string, object> htmlAttributes)
{
return ValidationMessageHelper(htmlHelper,
ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData),
ExpressionHelper.GetExpressionText(expression),
validationMessage,
htmlAttributes);
}
[SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Normalization to lowercase is a common requirement for JavaScript and HTML values")]
private static MvcHtmlString ValidationMessageHelper(this HtmlHelper htmlHelper, ModelMetadata modelMetadata, string expression, string validationMessage, IDictionary<string, object> htmlAttributes)
{
string modelName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
FormContext formContext = htmlHelper.ViewContext.FormContext;
if (!htmlHelper.ViewData.ModelState.ContainsKey(modelName) && formContext == null)
{
return null;
}
ModelState modelState = htmlHelper.ViewData.ModelState[modelName];
ModelErrorCollection modelErrors = (modelState == null) ? null : modelState.Errors;
ModelError modelError = (((modelErrors == null) || (modelErrors.Count == 0)) ? null : modelErrors.FirstOrDefault(m => !String.IsNullOrEmpty(m.ErrorMessage)) ?? modelErrors[0]);
if (modelError == null && formContext == null)
{
return null;
}
TagBuilder builder = new TagBuilder("img");
builder.MergeAttributes(htmlAttributes);
builder.AddCssClass((modelError != null) ? HtmlHelper.ValidationMessageCssClassName : HtmlHelper.ValidationMessageValidCssClassName);
if (!String.IsNullOrEmpty(validationMessage))
{
builder.Attributes.Add("title", validationMessage);
}
else if (modelError != null)
{
builder.Attributes.Add("title", GetUserErrorMessageOrDefault(htmlHelper.ViewContext.HttpContext, modelError, modelState));
}
if (formContext != null)
{
bool replaceValidationMessageContents = String.IsNullOrEmpty(validationMessage);
if (htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled)
{
builder.MergeAttribute("data-valmsg-for", modelName);
builder.MergeAttribute("data-valmsg-replace", replaceValidationMessageContents.ToString().ToLowerInvariant());
builder.MergeAttribute("data-val-usetitle", "true");
}
else
{
FieldValidationMetadata fieldMetadata = ApplyFieldValidationMetadata(htmlHelper, modelMetadata, modelName);
// rules will already have been written to the metadata object
fieldMetadata.ReplaceValidationMessageContents = replaceValidationMessageContents; // only replace contents if no explicit message was specified
// client validation always requires an ID
builder.GenerateId(modelName + "_validationMessage");
fieldMetadata.ValidationMessageId = builder.Attributes["id"];
}
}
return builder.ToMvcHtmlString(TagRenderMode.Normal);
}
}
internal static class TagBuilderExtensions
{
internal static MvcHtmlString ToMvcHtmlString(this TagBuilder tagBuilder, TagRenderMode renderMode)
{
return new MvcHtmlString(tagBuilder.ToString(renderMode));
}
}
答案 1 :(得分:0)
您发布的所有javascript和css都是由验证库为您完成的。您需要做的就是为模型添加验证属性,然后放置验证消息和摘要html / razor标记。
型号:
public class LogOnModel
{
[Required]
[Display(Name = "Username")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
}
查看:
<div class="editor-label">
@Html.LabelFor(m => m.UserName)*
</div>
<div class="editor-field">
@Html.TextBoxFor(m => m.UserName, new { autocomplete = "off" })
@Html.ValidationMessageFor(m => m.UserName, "")
</div>
<div class="editor-label">
@Html.LabelFor(m => m.Password)*
</div>
<div class="editor-field">
@Html.PasswordFor(m => m.Password, new { autocomplete = "off" })
@Html.ValidationMessageFor(m => m.Password, "")
</div>