У меня есть форма с проверкой на стороне клиента, и при вводе ошибки
обнаруживается, изменяется атрибут класса поля ввода; Он изменен, чтобы включить класс "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.





Нашел простое решение! Добавьте прослушиватель изменений 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, заполняемый с помощью вспомогательного тега при проверке на стороне сервера. См. ответ Адама Саймона об изменениях на стороне сервера.