I am trying to implement server side validation, by changing the class of an HTML child element within a TagHelper. The TagHelper is the "kendo-datepicker", however the current code modifies the class of the "span" tag and I would like to modify the class of the child "input" tag.
After some research it appears GetChildContentAsync may be useful, but all my attempts to use it are failing.
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");
}
}
}
}
}
Current (incorrect) HTML Output:
<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>
2
Answers
A very raw idea would be to do
and then get the content via
GetContent
as astring
and then parse thisstring
and thenSetContent
after you added theclass
. This is an admittedly dirty solution we should only resort to if there is nothing else that we can do.Alternatively, you could look into
context.Items
and see whether the input is there under some key. If so, then you could work with that one.I think the simplest way would be:
Note: if your HTML structure ever changes to include a second input, this will require updating.
String manipulation isn’t exactly the preferred method for doing this, but without additional context about your issue, it’s the most straightforward. Depending on your environment,
SetHtmlContent()
may cause problems. If that’s the case, remove both leading<
in the Regex and updateSetHtmlContent()
toSetContent()
. I only included it for the extremely minor performance boost of skipping a call toHTMLEncoder.Encode()
.