簡體   English   中英

如何使用 ASP.NET Core 更改輸入字段的客戶端驗證錯誤 CSS 類?

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

我有一個帶有客戶端驗證的表單,當檢測到錯誤輸入時,會更改輸入字段的類屬性; 它已更改為包括"input-validation-error"類。

我想更改這個類,以便不使用它而是使用 Bootstraps 類"is-invalid"

我嘗試使用 ASP.NET Core 的TagHelpers ,但這沒有效果; 我相信這不會起作用,因為助手僅在加載“整個頁面”時才起作用,它對客戶端驗證沒有幫助。

當我在 .NET 項目中搜索時,找到了在"Unobtrusive validation support library for jQuery"定義的 css 類。

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

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 的代碼片段。

[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

我也遇到過這個問題,但我真的不喜歡在客戶端修復它的想法,因為 jQuery 技巧只有在瀏覽器中啟用 JavaScript 時才有效。 因此,我認為應該在服務器端解決這個問題。

不幸的是,該框架沒有提供配置驗證相關 css 類的方法, 這些字符串只是硬編碼的

然而,這些字段不是常量而是聲明為靜態的,因此我們可以在運行時通過反射來改變它們的值(就像這里介紹的那樣)。 但這類事情是骯臟的黑客,應該是我們最后的手段。

OP 的自定義標簽助手的想法看起來好多了。 但它有一個缺點:它只修復標簽助手生成的標記。 經典的Html.TextBox(...)類的方法仍然會被打破。

那么,我們還能做得更好嗎? 幸運的是,是的!

Html和標簽助手實現都在IHtmlGenerator使用IHtmlGenerator服務來生成它們的標記。 由於 ASP.NET Core 的模塊化架構,我們可以提供此服務的定制版本。 (更重要的是,我們甚至可以在不復制一堆代碼的情況下做到這一點,因為默認實現將相關方法聲明為虛擬方法。)

因此,我可以想出這個解決方案:

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

我知道這已經發布了一段時間。

ASP.NET Core MVC 可以使用 JQuery 驗證和不顯眼的腳本教程在這里進行數據注釋驗證,自定義驗證器對象並配置validClasserrorClass屬性,如下所示:

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

您可以將上述代碼片段放在_ValidationScriptsPartial.cshtml文件中。 現在,如果您運行您的應用程序,您將能夠看到 Bootstrap 驗證樣式消息。

找到了一個簡單的解決方案! input元素添加 CSS 更改偵聽器; 此示例向“輸入”元素添加了一個偵聽器,但也可以應用於其他元素。

取自此處jQuery - 如果 CSS 類發生更改則觸發事件

這是我的實現,請注意我修改了偵聽​​器中的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM