2012-01-23 14 views
2

ASP.NET MVC3カスタム検証メッセージ行動

私は、私が釘付けしたことをかなり確信しているとして、バリデータがMVC3でどのように機能するかを説明するようにしてくださいこれ以上の答えをMVC3のバリデータは、ボックスの外にどのように機能するかを非常に明確です。私が達成しようとしているのは、最初の段落に示すように、スパンタグのタイトルとして表示される検証エラーメッセージです。

私はMVC3でこれを複製することができましたが、私がそれを行った方法がベストプラクティスに従っているかどうかはわかりません。私は、同じことを達成するためのよりよい方法があるかどうかに関して、どんなインプットにも感謝します。 jquery.validate.unobtrusive.jsを変更せずに済ませることができれば本当に素晴らしいことです。

それでは、私が行っていることである。

1)) 3その有効のようにメッセージを追加するかどうかを判断するために新しい属性を追加しながら、「*」 2)検証メッセージを隠しする検証メッセージを設定します。タイトル 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(); 
      } 
     } 

答えて

3

私が何をやったことはクリーンな方法だと思います。 jquery.validate.unobtrusive.jsを変更する方法はありません。なぜなら、MVCの拡張機能は、古い学校asp.netの方法論に従っていないからです。

私は独自のカスタム検証拡張calld ValidationIconFor()を作成しました.1つのイメージがそのタイトルがエラーメッセージに設定されて表示され、上記の修正されたバージョンのコードを使用しました。

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)); 
    } 
} 
+0

ありがとう - うれしい私は完全に怒っていなかった:) –

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> 
+0

おかげで、それは明らかに私の質問は、十分に明確ではないので、私は意志今すぐ編集してください。とにかく私は妥当性検査がどのように働くか尋ねていません。カスタマイズした方法(私のコードを慎重に確認して、正規のバリデータとはかなり異なることをしている場合)がカスタマイズを行う正しい方法かどうかを尋ねています。 –

関連する問題