简体   繁体   English

如何使用 ASP.NET Core 更改输入字段的客户端验证错误 CSS 类?

[英]How to alter the client-side validation error CSS class of an input field using ASP.NET Core?

I have a form with client side validation, and when an error input is detected, a class attribute is changed of an input field;我有一个带有客户端验证的表单,当检测到错误输入时,会更改输入字段的类属性; It is changed to include "input-validation-error" class.它已更改为包括"input-validation-error"类。

I want to change this class, in order not to use it but instead use Bootstraps class "is-invalid" .我想更改这个类,以便不使用它而是使用 Bootstraps 类"is-invalid"

I tried using ASP.NET Core's TagHelpers , but this has no effect;我尝试使用 ASP.NET Core 的TagHelpers ,但这没有效果; I believe that this will not work as the helpers will only work if the "whole page" is loaded, it does not help with client side validation.我相信这不会起作用,因为助手仅在加载“整个页面”时才起作用,它对客户端验证没有帮助。

When I search in the .NET project one finds the css class defined in, the "Unobtrusive validation support library for jQuery" .当我在 .NET 项目中搜索时,找到了在"Unobtrusive validation support library for jQuery"定义的 css 类。

What is the best way to change this class?更改此类的最佳方法是什么?

Could CSS help by changing a class from one to the other? CSS 可以通过将一个类从一个类更改为另一个类来提供帮助吗? (overriding the original class, not sure if this is possible) (覆盖原始类,不确定这是否可能)

Or should one use JavaScript to reconfigure JQuery ?或者应该使用 JavaScript 来重新配置JQuery吗?

Here is my TagHelper, adding the helpers: validation-for,validation-error-class,validation-valid-class这是我的 TagHelper,添加助手: validation-for,validation-error-class,validation-valid-class

The Form/Html...表格/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>

Here is a snippet of the code for my TagHelper.这是我的 TagHelper 的代码片段。

[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);                
        }          
    }
}

New Approach not working 100%.新方法不起作用 100%。

I have tried an alternative approach, by modifying the jQuery defaultOptions , changing the errorClass and the validClass.我尝试了另一种方法,通过修改jQuery defaultOptions ,更改 errorClass 和 validClass。

Snippet of the Code found here on [ https://github.com/brecons/jquery-validation-unobtrusive-bootstrap][gitHub]在 [ https://github.com/brecons/jquery-validation-unobtrusive-bootstrap][gitHub]上找到的代码片段

function ($) {
    if($.validator && $.validator.unobtrusive){
        var defaultOptions = {
            validClass: 'is-valid',
            errorClass: 'is-invalid',

This works for the errorClass, but for me the validClass remains unchanged, it remains to be named valid .这适用于 errorClass,但对我来说 validClass 保持不变,它仍然被命名为valid

I have encountered this issue too but I don't really like the idea of fixing it at client-side as the jQuery-trick works only when JavaScript is enabled in the browser.我也遇到过这个问题,但我真的不喜欢在客户端修复它的想法,因为 jQuery 技巧只有在浏览器中启用 JavaScript 时才有效。 Because of this, I think the problem should be addressed at server-side.因此,我认为应该在服务器端解决这个问题。

Unfortunately, the framework doesn't provide a way to configure the validation-related css classes, these strings are simply hard-coded .不幸的是,该框架没有提供配置验证相关 css 类的方法, 这些字符串只是硬编码的

However, these fields are not constants but declared as static, so we may change their value at run-time via reflection (somehow like presented here ).然而,这些字段不是常量而是声明为静态的,因此我们可以在运行时通过反射来改变它们的值(就像这里介绍的那样)。 But these kinds of things are dirty hacks which should be our last resort.但这类事情是肮脏的黑客,应该是我们最后的手段。

OP's idea of a custom tag helper looks much better. OP 的自定义标签助手的想法看起来好多了。 But it has a shortcoming: it only fixes markup generated by tag helpers.但它有一个缺点:它只修复标签助手生成的标记。 The classic, Html.TextBox(...) -like approach would be still broken.经典的Html.TextBox(...)类的方法仍然会被打破。

So, can we do any better?那么,我们还能做得更好吗? Luckily, yes!幸运的是,是的!

Both Html and tag helper implementations use the IHtmlGenerator service under the hood to generate their markup. Html和标签助手实现都在IHtmlGenerator使用IHtmlGenerator服务来生成它们的标记。 Thanks to the modular architecture of ASP.NET Core, we can provide a customized version of this service.由于 ASP.NET Core 的模块化架构,我们可以提供此服务的定制版本。 (What's more, we can even do this without copying a bunch of code as the default implementation declares the relevant methods as virtual.) (更重要的是,我们甚至可以在不复制一堆代码的情况下做到这一点,因为默认实现将相关方法声明为虚拟方法。)

Thus, I could come up with this solution:因此,我可以想出这个解决方案:

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

All that is left is to configure DI to resolve this custom implementation by adding the following at the end of the Startup.ConfigureService method:剩下的就是通过在Startup.ConfigureService方法的末尾添加以下内容来配置 DI 以解决此自定义实现:

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

I know this has been posted for a while.我知道这已经发布了一段时间。

ASP.NET Core MVC can use JQuery validation with unobtrusive script Tutorial here for data annotations validation, customize the validator object and configure the validClass and errorClass properties, like this: ASP.NET Core MVC 可以使用 JQuery 验证和不显眼的脚本教程在这里进行数据注释验证,自定义验证器对象并配置validClasserrorClass属性,如下所示:

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

You can place the above code snippet in the _ValidationScriptsPartial.cshtml file.您可以将上述代码片段放在_ValidationScriptsPartial.cshtml文件中。 And now if you run your application, you will be able to see the Bootstrap validation style messages.现在,如果您运行您的应用程序,您将能够看到 Bootstrap 验证样式消息。

Found a simple solution!找到了一个简单的解决方案! Add a CSS change listener to the input element;input元素添加 CSS 更改侦听器; This example adds a listener to the "input" element, but could also be applied to other elements.此示例向“输入”元素添加了一个侦听器,但也可以应用于其他元素。

Taken from here jQuery - Fire event if CSS class changed取自此处jQuery - 如果 CSS 类发生更改则触发事件

Here is my implementation, notice that I modify the CSS in the listener, which could potentially cause a stack overflow .这是我的实现,请注意我修改了侦听​​器中的 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 自定义客户端验证未在 ASP.NET 内核中触发 - Custom Client-Side Validation not triggering in ASP.NET Core 在 ASP.NET Core MVC 中不工作的 bool 字段的不显眼的客户端验证 - Unobtrusive client-side validation for bool field not working in ASP.NET Core MVC 如何在 ASP.NET Core 3.1 MVC 中进行RequiredIf 客户端和服务器端验证? - How to make RequiredIf Client-side and server-side validation in ASP.NET Core 3.1 MVC? 如何在ASP.NET Core 2.0中的自定义验证属性中进行客户端验证? - How To Do Client-Side Validation In Custom Validation Attribute In ASP.NET Core 2.0? 使用javascript(客户端验证)更改ASP.NET自定义验证程序的错误消息? - Change error message for ASP.NET custom validator using javascript (client-side validation)? 用于客户端和服务器端验证的 ASP.NET Core 重用代码 - ASP.NET Core Reuse Code for Client-Side and Server-Side Validation ASP.Net Core 客户端验证:是否存在“验证成功”的 DOM 事件? - ASP.Net Core client-side validation: is there a “validation succeeded” DOM event? 在字段级别禁用 asp.net core 中的客户端验证 - Disable client side validation in asp.net core at field level 在C#ASP.NET Core 2.2的客户端上实现简单的验证 - Implementing simple validation on the client-side in C# ASP.NET Core 2.2 ASP.Net Core MVC - 自定义属性的客户端验证 - ASP.Net Core MVC - Client-side validation for custom attribute
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM