Как изменить класс CSS ошибки проверки на стороне клиента поля ввода с помощью ASP.NET Core?

У меня есть форма с проверкой на стороне клиента, и при вводе ошибки обнаруживается, изменяется атрибут класса поля ввода; Он изменен, чтобы включить класс "input-validation-error".

Я хочу изменить этот класс, чтобы не использовать его, а вместо этого использовать класс Bootstraps "is-invalid".

Я пытался использовать TagHelpers ASP.NET Core, но это не дало результата; Я считаю, что это не сработает, поскольку помощники будут работать только в том случае, если загружена «целая страница», это не помогает при проверке на стороне клиента.

Когда я ищу в проекте .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.

[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%.

Я попробовал альтернативный подход, изменив jQuerydefaultOptions, изменив 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.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
1 745
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Нашел простое решение! Добавьте прослушиватель изменений CSS к элементу input; В этом примере прослушиватель добавляется к элементу input, но его можно применить и к другим элементам.

Взято отсюда jQuery — событие Fire, если класс 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>

Я тоже столкнулся с этой проблемой, но мне не очень нравится идея исправить ее на стороне клиента, поскольку jQuery-трюк работает только тогда, когда в браузере включен JavaScript. Из-за этого я думаю, что проблема должен должна решаться на стороне сервера.

К сожалению, фреймворк не предоставляет возможности настройки классов css, связанных с проверкой, эти строки просто жестко закодированы.

Однако эти поля не являются константами, а объявлены как статические, поэтому мы можем изменить их значение во время выполнения с помощью отражения (что-то вроде представленного здесь). Но такие вещи — грязные хаки, которые должны быть нашим последним средством.

Идея ОП о вспомогательном вспомогательном теге выглядит намного лучше. Но у него есть недостаток: он исправляет только разметку, созданную помощниками тегов. Классический Html.TextBox(...)-подобный подход все равно будет нарушен.

Итак, можем ли мы сделать лучше? К счастью, да!

Как Html, так и реализации вспомогательных тегов используют сервис 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));
}

Все, что осталось, — настроить DI для разрешения этой пользовательской реализации, добавив следующее в конце метода Startup.ConfigureService:

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

Я знаю, что это было опубликовано некоторое время.

ASP.NET Core MVC может использовать проверку JQuery с ненавязчивым сценарием Учебник здесь для проверки аннотаций данных, настраивать объект проверки и настраивать свойства validClass и errorClass, например:

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

Вы можете поместить приведенный выше фрагмент кода в файл _ValidationScriptsPartial.cshtml. И теперь, если вы запустите свое приложение, вы сможете увидеть сообщения в стиле проверки Bootstrap.

Это изменяет классы проверки на стороне клиента, но не изменяет класс css, заполняемый с помощью вспомогательного тега при проверке на стороне сервера. См. ответ Адама Саймона об изменениях на стороне сервера.

Steven Quick 24.08.2020 04:02

Другие вопросы по теме