【问题标题】:How to alter the client-side validation error CSS class of an input field using ASP.NET Core?如何使用 ASP.NET Core 更改输入字段的客户端验证错误 CSS 类?
【发布时间】:2019-05-08 01:44:56
【问题描述】:

我有一个带有客户端验证的表单,当输入错误时 检测到,改变输入字段的类属性;改为包含"input-validation-error" 类。

我想更改这个类,以便不使用它,而是使用 Bootstraps 类"is-invalid"

我尝试使用 ASP.NET Core 的TagHelpers,但这没有效果; 我相信这不会起作用,因为只有加载“整个页面”时,帮助程序才会起作用,它对客户端验证没有帮助。

当我在 .NET 项目中搜索时,会发现其中定义的 css 类, "Unobtrusive validation support library for jQuery"

更改此类的最佳方法是什么?

CSS 可以通过将一个类从一个类更改为另一个类来提供帮助吗? (覆盖原来的类,不确定是否可行)

还是应该使用 JavaScript 重新配置JQuery

这是我的 TagHelper,添加助手:validation-for,validation-error-class,validation-valid-class

表单/Html...

<input type="email" asp-for="Email" id="inputEmail" class="form-control" placeholder="Email address" required
                            validation-for="Email" validation-error-class="is-invalid" validation-valid-class="is-valid"/>
                            <span class="small" asp-validation-for="Email"></span>

这是我的 TagHelper 代码的 sn-p。

[HtmlTargetElement("input", Attributes = "validation-for,validation-error-class,validation-valid-class")]
public class ValidationErrorClassTagHelper : TagHelper
{
    [HtmlAttributeName("validation-for")]
    public ModelExpression For { get; set; }

    [HtmlAttributeName("validation-error-class")]
    public string ErrorClass { get; set; }
    [HtmlAttributeName("validation-valid-class")]
    public string ValidClass { get; set; }


    [HtmlAttributeNotBound]
    [ViewContext]
    public ViewContext ViewContext { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.RemoveClass(ErrorClass,HtmlEncoder.Default);
        output.RemoveClass(ValidClass,HtmlEncoder.Default);

        if (ViewContext.ViewData.ModelState.IsValid) {                
            output.AddClass(ValidClass,HtmlEncoder.Default);
        } else 
        {
            output.AddClass(ErrorClass,HtmlEncoder.Default);                
        }          
    }
}

新方法无法 100% 发挥作用。

我尝试了另一种方法,通过修改jQuery defaultOptions,更改errorClass 和validClass。

在 [https://github.com/brecons/jquery-validation-unobtrusive-bootstrap][gitHub]

上找到的代码片段
function ($) {
    if($.validator && $.validator.unobtrusive){
        var defaultOptions = {
            validClass: 'is-valid',
            errorClass: 'is-invalid',

这适用于errorClass,但对我来说validClass保持不变, 它仍然被命名为valid

【问题讨论】:

    标签: c# jquery asp.net-core


    【解决方案1】:

    我也遇到过这个问题,但我不太喜欢在客户端修复它的想法,因为 jQuery 技巧仅在浏览器中启用 JavaScript 时才有效。因此,我认为问题应该在服务器端解决。

    不幸的是,该框架没有提供配置验证相关 css 类的方法,these strings are simply hard-coded

    但是,这些字段不是常量,而是声明为静态的,因此我们可以在运行时通过反射更改它们的值(不知何故,就像呈现的 here)。但这类事情是肮脏的黑客行为,应该是我们最后的手段。

    OP 的自定义标签助手的想法看起来要好得多。但它有一个缺点:它只修复了标签助手生成的标记。经典的Html.TextBox(...) 式方法仍然会被打破。

    那么,我们可以做得更好吗?幸运的是,是的!

    Html 和标签助手实现都在底层使用 IHtmlGenerator 服务来生成它们的标记。得益于 ASP.NET Core 的模块化架构,我们可以提供该服务的定制版本。 (更重要的是,我们甚至可以在不复制一堆代码的情况下做到这一点,因为default implementation 将相关方法声明为虚拟。)

    因此,我可以想出这个解决方案:

    public sealed class CustomHtmlGenerator : DefaultHtmlGenerator
    {
        private static IHtmlHelper GetHtmlHelperFor(ViewContext viewContext)
        {
            const string htmlHelperViewDataKey = nameof(CustomHtmlGenerator) + "_" + nameof(IHtmlHelper);
    
            if (!viewContext.ViewData.TryGetValue(htmlHelperViewDataKey, out var htmlHelperObj) || !(htmlHelperObj is IHtmlHelper htmlHelper))
                viewContext.ViewData[htmlHelperViewDataKey] = htmlHelper = GetViewHtmlHelper(viewContext) ?? CreateHtmlHelper(viewContext);
    
            return htmlHelper;
    
            static IHtmlHelper GetViewHtmlHelper(ViewContext viewContext)
            {
                if (!(viewContext.View is RazorView razorView))
                    return null;
    
                dynamic razorPage = razorView.RazorPage;
    
                try { return (IHtmlHelper)razorPage.Html; }
                catch { return null; }
            }
    
            static IHtmlHelper CreateHtmlHelper(ViewContext viewContext)
            {
                var htmlHelper = viewContext.HttpContext.RequestServices.GetRequiredService<IHtmlHelper>();
                (htmlHelper as IViewContextAware)?.Contextualize(viewContext);
                return htmlHelper;
            }
        }
    
        private static TagBuilder AddBootstrapValidationCssClasses(ViewContext viewContext, string expression, TagBuilder tagBuilder)
        {
            // we need to get the model property key from the expression, which functionality is buried in an internal class unfortunately
            // (https://github.com/dotnet/aspnetcore/blob/v3.1.6/src/Mvc/Mvc.ViewFeatures/src/NameAndIdProvider.cs#L147)
            // however, this internal API is exposed via the IHtmlHelper.Name method:
            // (https://github.com/dotnet/aspnetcore/blob/v3.1.6/src/Mvc/Mvc.ViewFeatures/src/HtmlHelper.cs#L451)
            var htmlHelper = GetHtmlHelperFor(viewContext);
            var fullName = htmlHelper.Name(expression);
    
            if (viewContext.ModelState.TryGetValue(fullName, out var entry))
            {
                if (entry.ValidationState == ModelValidationState.Invalid)
                    tagBuilder.AddCssClass("is-invalid");
                else if (entry.ValidationState == ModelValidationState.Valid)
                    tagBuilder.AddCssClass("is-valid");
            }
    
            return tagBuilder;
        }
    
        public CustomHtmlGenerator(IAntiforgery antiforgery, IOptions<MvcViewOptions> optionsAccessor, IModelMetadataProvider metadataProvider, IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder, ValidationHtmlAttributeProvider validationAttributeProvider)
            : base(antiforgery, optionsAccessor, metadataProvider, urlHelperFactory, htmlEncoder, validationAttributeProvider) { }
    
        protected override TagBuilder GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, string expression, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes) =>
            AddBootstrapValidationCssClasses(viewContext, expression, base.GenerateInput(viewContext, inputType, modelExplorer, expression, value, useViewData, isChecked, setId, isExplicitValue, format, htmlAttributes));
    
        public override TagBuilder GenerateSelect(ViewContext viewContext, ModelExplorer modelExplorer, string optionLabel, string expression, IEnumerable<SelectListItem> selectList, ICollection<string> currentValues, bool allowMultiple, object htmlAttributes) =>
            AddBootstrapValidationCssClasses(viewContext, expression, base.GenerateSelect(viewContext, modelExplorer, optionLabel, expression, selectList, currentValues, allowMultiple, htmlAttributes));
    
        public override TagBuilder GenerateTextArea(ViewContext viewContext, ModelExplorer modelExplorer, string expression, int rows, int columns, object htmlAttributes) =>
            AddBootstrapValidationCssClasses(viewContext, expression, base.GenerateTextArea(viewContext, modelExplorer, expression, rows, columns, htmlAttributes));
    }
    

    剩下的就是通过在Startup.ConfigureService 方法的末尾添加以下内容来配置 DI 以解决此自定义实现:

    services.Replace(ServiceDescriptor.Singleton<IHtmlGenerator, CustomHtmlGenerator>());
    

    【讨论】:

      【解决方案2】:

      我知道这已经发布了一段时间。

      ASP.NET Core MVC 可以使用 JQuery 验证和不显眼的脚本 Tutorial here 进行数据注释验证,自定义验证器对象并配置 validClasserrorClass 属性,如下所示:

      <script>
              
      var settings = {
              validClass: "is-valid",
              errorClass: "is-invalid"
          
          }; 
          $.validator.setDefaults(settings);
          $.validator.unobtrusive.options = settings;
      </script>
      

      可以将上面的代码sn-p放到_ValidationScriptsPartial.cshtml文件中。现在,如果您运行您的应用程序,您将能够看到 Bootstrap 验证样式消息。

      【讨论】:

      • 这确实会更改客户端验证类,但不会更改通过标签助手从服务器端验证填充的 css 类。有关服务器端更改,请参阅 Adam Simon 的答案。
      【解决方案3】:

      找到了一个简单的解决方案!向input 元素添加CSS 更改监听器; 此示例将侦听器添加到“输入”元素,但也可以应用于其他元素。

      取自这里jQuery - Fire event if CSS class changed

      这是我的实现,请注意我修改了侦听​​器中的 CSS,这可能会导致 堆栈溢出

      <script type="text/javascript">
      // Create a closure
      (function() {
      
          var originalAddClassMethod = jQuery.fn.addClass;
      
          jQuery.fn.addClass = function() {
              // Execute the original method.
              var result = originalAddClassMethod.apply(this, arguments);
      
              // trigger a custom event
              // stop recursion...
              if ((arguments[0] != "is-valid") && (arguments[0] != "is-invalid")) {
                  jQuery(this).trigger('cssClassChanged');
              }            
      
              // return the original result
              return result;
          }
      })();
      
      // document ready function
      $(function() {
          $("input").bind('cssClassChanged', function(){ 
              // cleanup
              if ($(this).hasClass("is-valid")) {
                  $(this).removeClass("is-valid");
              }
              if ($(this).hasClass("is-invalid")) {
                  $(this).removeClass("is-invalid");
              }
      
              // remap the css classes to that of BootStrap 
              if ($(this).hasClass("input-validation-error")) {
                  $(this).addClass("is-invalid");        
              }
      
              if ($(this).hasClass("valid")) {
                  $(this).addClass("is-valid");        
              }
          });
      });
      </script>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-06
        • 1970-01-01
        • 2012-11-08
        • 2013-07-23
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2019-04-29
        相关资源
        最近更新 更多