I noticed in my project that all my form fields follow the same pattern. A typical example is:
<div class="col-x-x">
<label asp-for="Property"></label>
<span message="description">
<input asp-for="Property" />
<span asp-validation-for="Property"></span>
</div>
I would love to have some way of grouping this code so that i simply pass it the property on the model and it outputs the correct HTML. e.g.:
<form-field for="Property" ...>
or
@Html.StringFormField(...)
The issue I am having is that whatever method I try, the html outputted is the original html above, and not the html that is generated from the tag helpers. I have tried both methods and neither have been successful. Additionally I have tried to create a razor function, but all my attempts fail to compile, and I can't make a partial view work as I haven't been able to find a way to get the property information after passing a string to a view.
My latest attempt was using a tag helper, however this had the same issue mentioned previously. The latest version of the code is as follows:
[HtmlTargetElement("form-field", Attributes = "for")]
public class FormFieldTagHelper : TagHelper
{
[HtmlAttributeName("for")]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag;
var contentBuilder = new HtmlContentBuilder();
contentBuilder.AppendHtmlLine($"<label asp-for=\"{For}\"></label>");
contentBuilder.AppendHtmlLine($"<span message=\"description.\"></span>");
contentBuilder.AppendHtmlLine($"<input asp-for=\"{For}\"/>");
contentBuilder.AppendHtmlLine($"<span asp-validation-for=\"{For}\"/></span>");
output.Content.SetHtmlContent(contentBuilder);
}
}
There is an issue addressing this (with no solution) which suggested the order of the imports was a potential issue, so my imports are as follows:
@addTagHelper Project.Web.Features.Shared.*, Project.Web
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
Any solution would be welcome, either for a tag helper or another method.
You could use IHtmlGenerator to generate these elements, refer to my below demo code:
[HtmlTargetElement("form-field", Attributes = "for")]
public class FormFieldTagHelper : TagHelper
{
[HtmlAttributeName("for")]
public ModelExpression For { get; set; }
private readonly IHtmlGenerator _generator;
[ViewContext]
public ViewContext ViewContext { get; set; }
public FormFieldTagHelper(IHtmlGenerator generator)
{
_generator = generator;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
using (var writer = new StringWriter())
{
writer.Write(@"<div class=""form-group"">");
var label = _generator.GenerateLabel(
ViewContext,
For.ModelExplorer,
For.Name, null,
new { @class = "control-label" });
label.WriteTo(writer, NullHtmlEncoder.Default);
writer.Write(@"<span message=""description.""></span>");
var textArea = _generator.GenerateTextBox(ViewContext,
For.ModelExplorer,
For.Name,
For.Model,
null,
new { @class = "form-control" });
textArea.WriteTo(writer, NullHtmlEncoder.Default);
var validationMsg = _generator.GenerateValidationMessage(
ViewContext,
For.ModelExplorer,
For.Name,
null,
ViewContext.ValidationMessageElement,
new { @class = "text-danger" });
validationMsg.WriteTo(writer, NullHtmlEncoder.Default);
writer.Write(@"</div>");
output.Content.SetHtmlContent(writer.ToString());
}
}
}
View:
<form-field for="ManagerName"></form-field>
Result:

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With