Reputation:
I'm writing a simple pagination TagHelper, where I want the output to look like this:
<ul>
<li><a href="...">Some Text</a></li>
<li><a href="...">Some Other Text</a></li>
...
</ul>
I had the idea that in defining my class I'd generate "a" elements, and decorate them with asp-controller, asp-action, etc., attributes, which would get rendered as the correct href link. Here's the code I came up with:
protected TagBuilder CreatePageLink( int page, bool enabled, string inner )
{
TagBuilder a = new TagBuilder( "a" );
a.MergeAttribute( "asp-controller", AspController );
a.MergeAttribute( "asp-action", AspAction );
a.MergeAttribute( "asp-route-page", page.ToString() );
a.MergeAttribute( "asp-route-itemsPerPage", ItemsPerPage.ToString() );
a.MergeAttribute( "title", $"goto page {page}" );
if( !enabled ) a.AddCssClass( "disabled" );
if( (page == Page) && String.IsNullOrEmpty(inner) ) a.AddCssClass( "active" );
if( String.IsNullOrEmpty( inner ) ) inner = page.ToString();
a.InnerHtml.AppendHtml( inner );
TagBuilder li = new TagBuilder( "li" );
li.InnerHtml.Append( a );
return li;
}
But it doesn't work. The "MVC magic attributes" like asp-controller show up in the output, but the resulting links don't work. I have to add, in code, a specific href attribute to the embedded "a" element for the link to work.
How do I go about nesting TagHelpers, like the LinkTagHelper, inside my own custom TagHelper?
Upvotes: 4
Views: 1800
Reputation: 416
This video on tag helpers might be helpful: https://channel9.msdn.com/Shows/Web+Camps+TV/Update-on-TagHelpers-with-Taylor-Mullen
Skip ahead to about 35 minutes in.
Also they put the code up on github: https://github.com/NTaylorMullen/WebCampsTV_TagHelpers1
The part that you will find relevant is here:
[OutputElementHint("ul")]
public class ControllerNavigationTagHelper : TagHelper
{
public ControllerNavigationTagHelper(IUrlHelper urlHelper)
{
UrlHelper = urlHelper;
}
private IUrlHelper UrlHelper { get; }
public Type ControllerType { get; set; }
public string Exclude { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "ul";
var actionNames = ControllerType.GetTypeInfo().DeclaredMethods
.Where(methodInfo => methodInfo.IsPublic)
.Select(methodInfo => methodInfo.Name);
var controllerName = ControllerType.Name;
if (controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
{
controllerName = controllerName.Substring(0, controllerName.Length - "Controller".Length);
}
foreach (var name in actionNames)
{
if (!string.Equals(name, Exclude, StringComparison.OrdinalIgnoreCase))
{
var displayName =
string.Equals(name, "Index", StringComparison.OrdinalIgnoreCase) ? controllerName : name;
output.PostContent.Append($"<li><a href='{UrlHelper.Action(name, controllerName)}'>{displayName}</a></li>");
}
}
}
}
The basic premises is that there is an IUrlHelper
service, I think built in to mvc (asp.net core mvc), that can be injected into your tag helper which you can use to construct the reference.
Once the IUrlHelper
is injected you can use it to construct the url:
UrlHelper.Action(name, controllerName)
Upvotes: 2