I recently ran into a situation where I would like to use a tag helper within a tag helper. I looked around and couldn't find anyone else trying to do this, am I using a poor convention or am I missing documentation?
Ex. Tag Helper A outputs HTML that contains another tag helper.
Ex.
[HtmlTargetElement("tag-name")]
public class RazorTagHelper : TagHelper
{
public override void Process(TagHelperContext context, TagHelperOutput output)
{
StringBuilder sb = new StringBuilder();
sb.Append("<a asp-action=\"Home\" ");
output.Content.SetHtmlContent(sb.ToString());
}
}
Is there a way for me to process the <a asp-action> </a>
tag helper from C#? Or to reprocess the output HTML with tag helpers?
No you cannot. TagHelpers are a Razor parse time feature.
One alternative is creating a TagHelper and manually invoking its ProcessAsync/Process method. Aka:
var anchorTagHelper = new AnchorTagHelper
{
Action = "Home",
};
var anchorOutput = new TagHelperOutput("a", new TagHelperAttributeList(), (useCachedResult, encoder) => new HtmlString());
var anchorContext = new TagHelperContext(
new TagHelperAttributeList(new[] { new TagHelperAttribute("asp-action", new HtmlString("Home")) }),
new Dictionary<object, object>(),
Guid.NewGuid());
await anchorTagHelper.ProcessAsync(anchorContext, anchorOutput);
output.Content.SetHtmlContent(anchorOutput);
I don't know if this works for your scenario, but it is possible to inherit from the AnchorTagHelper and then do your customisations like this.
public class TestTagHelper : AnchorTagHelper
{
public TestTagHelper(IHtmlGenerator htmlGenerator) : base(htmlGenerator) { }
public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
// Replaces <test> with <a> tag
output.TagName = "a";
//do custom processing
output.Attributes.SetAttribute("class", "custom-class");
//let the base class generate the href
base.ProcessAsync(context, output);
}
}
Then you can just use this tag helper in your view with all the built-in goodness of the default AnchorTagHelper
.
<test asp-action="Index" asp-route-id="5"></test>
If anyone's looking to reuse the built-in tag helpers from asp.net core, you can use the IHtmlGenerator instead. For reusing other types of tag helpers, I haven't found a simpler option then @N. Taylor Mullen answer
Here is how to reuse the asp-action tag helper:
[HtmlTargetElement("helplink")]
public class RazorTagHelper : TagHelper
{
private readonly IHtmlGenerator _htmlGenerator;
public RazorTagHelper(IHtmlGenerator htmlGenerator)
{
_htmlGenerator = htmlGenerator;
}
[ViewContext]
public ViewContext ViewContext { set; get; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "div";
output.TagMode = TagMode.StartTagAndEndTag;
var actionAnchor = _htmlGenerator.GenerateActionLink(
ViewContext,
linkText: "Home",
actionName: "Index",
controllerName: null,
fragment: null,
hostname: null,
htmlAttributes: null,
protocol: null,
routeValues: null
);
var builder = new HtmlContentBuilder();
builder.AppendHtml("Here's the link: ");
builder.AppendHtml(actionAnchor);
output.Content.SetHtmlContent(builder);
}
}