[英]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 驗證和不顯眼的腳本教程在這里進行數據注釋驗證,自定義驗證器對象並配置validClass
和errorClass
屬性,如下所示:
<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.