自定义验证 TagHelper:修改子元素

Custom Validation TagHelper: Modify Child Element

提问人:Reafidy 提问时间:8/14/2023 最后编辑:Reafidy 更新时间:9/19/2023 访问量:130

问:

我正在尝试通过更改 TagHelper 中 HTML 子元素的类来实现服务器端验证。TagHelper 是“kendo-datepicker”,但是当前代码修改了“span”标签的类,我想修改子“input”标签的类。

经过一番研究,GetChildContentAsync 似乎很有用,但我使用它的所有尝试都失败了。

Taghelper:

[HtmlTargetElement("kendo-datepicker")]
[HtmlTargetElement("select")]
[HtmlTargetElement("input")]
public class ValidationErrorClassTagHelper : TagHelper
{
    [HtmlAttributeNotBound]
    [ViewContext]
    public ViewContext ViewContext { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {

        //output.Attributes.ContainsName("class")

        if (context.TagName == "kendo-datepicker")
        {
            TagHelperAttribute taghelperAttribute = context.AllAttributes["for"];
            if (taghelperAttribute != null)
            {
           
                ModelExpression modelExpression = (ModelExpression)taghelperAttribute.Value;

                ViewContext.ViewData.ModelState.TryGetValue(modelExpression.Name, out ModelStateEntry entry);

                if (entry != null && entry.Errors.Any())
                {
                    output.Attributes.SetAttribute("class", "form-control " + "is-invalid");
                 
                }
            }
        }

    }
}

当前(不正确)HTML 输出:

<span class="k-datepicker k-input form-control is-invalid k-input-solid k-input-md k-rounded-md" style=""><input class="form-control k-input-inner valid" required="" data-val="true" data-val-required="Enter the date observed." id="ADR_Date" name="ADR.Date" type="text" value="6/07/2023" data-role="datepicker" role="combobox" aria-expanded="false" aria-haspopup="grid" aria-controls="ADR_Date_dateview" autocomplete="off" aria-disabled="false" aria-readonly="false" aria-describedby="ADR_Date-error" aria-invalid="false"><button aria-label="select" tabindex="-1" class="k-input-button k-button k-icon-button k-button-md k-button-solid k-button-solid-base" type="button" role="button"><span class="k-icon k-i-calendar k-button-icon"></span></button></span>

不幸的是,taghelperoutput 正在渲染 jquery 而不是 html:

PostElement = <script>kendo.syncReady(function(){jQuery("#ADR_Date").kendoDatePicker({"format":"d","value":new Date(2023,6,6,0,0,0,0)});});</script>
javascript jquery asp.net-core unobtrusive-validation 标记帮助程序

评论


答:

0赞 Lajos Arpad 8/19/2023 #1

一个非常原始的想法是做

TagHelperContent innerContent = await output.GetChildContentAsync();

然后通过 As a 获取内容,然后解析它,然后在添加 .这是一个公认的肮脏的解决方案,只有在我们无能为力的情况下,我们才应该求助于。GetContentstringstringSetContentclass

或者,您可以查看输入是否在某个键下。如果是这样,那么您可以使用那个。context.Items

1赞 Chuck Terry 8/24/2023 #2

我认为最简单的方法是:

if (entry != null && entry.Errors.Any()) {
  // Asynchronously get string containing child content
  string childContent = (await output.GetChildContentAsync()).GetContent();
  // Insert your classes by matching the opening input tag along with the class attribute and replacing it.
  string modifiedContent = Regex.Replace(
    childContent,
    Regex.Escape("<input class=\""),
    "<input class=\"form-control is-invalid ");
  // Update the output
  output.Content.SetHtmlContent(modifiedContent);
}

注意:如果您的 HTML 结构发生更改以包含第二个输入,则需要更新。

字符串操作并不是执行此操作的首选方法,但如果没有有关问题的其他上下文,这是最直接的方法。根据您的环境,可能会导致问题。如果是这种情况,请删除正则表达式中的前导,并更新为 .我只是为了跳过对 的调用而将它包含在内,以提高极小的性能。SetHtmlContent()<SetHtmlContent()SetContent()HTMLEncoder.Encode()

评论

0赞 Reafidy 9/19/2023
我刚刚发现没有子元素。taghelper输出为PostElement = <script>kendo.syncReady(function(){jQuery("#ADR_Date").kendoDatePicker({"format":"d","value":new Date(2023,6,6,0,0,0,0)});});</script>
1赞 Ramon Soarez 8/26/2023 #3

您可以使用 GetChildContentAsync() 修改“kendo-datepicker”标记助手中的“input”子元素,如下所示:

if (context.TagName == "kendo-datepicker")
    {
        TagHelperAttribute taghelperAttribute = context.AllAttributes["for"];
        if (taghelperAttribute != null)
        {
            ModelExpression modelExpression = (ModelExpression)taghelperAttribute.Value;

            ViewContext.ViewData.ModelState.TryGetValue(modelExpression.Name, out ModelStateEntry entry);

            if (entry != null && entry.Errors.Any())
            {
              
                var childContent = await output.GetChildContentAsync();
                var inputElement = childContent.FindDescendants("input").FirstOrDefault();
                if (inputElement != null)
                {
                    inputElement.Attributes.Add("class", "form-control is-invalid");
                }
            }
        }
    }
    

在此代码中,childContent.FindDescendants(“input”) 方法用于查找和检索 childContent 中与给定标记名称“input”匹配的所有后代元素 FirstOrDefault() 是用于从 返回的匹配元素集合中获取第一个元素的方法。FindDescendants(“输入”)。

试一试,让我们知道您是否设法正确解决了您的案件。

评论

0赞 Reafidy 9/19/2023
很抱歉耽搁了,不幸的是我有一段时间没有工作。我似乎在“FindDescendants”上缺少引用错误。我似乎找不到正确的参考。