Still using backend HTML logic.
ASP.NET Core makes things a lot more easier for us, backend developers. Though, accent today, is more on frontend development, still, for reasons of security for instance, backend state management is still used.
Now take a look at this tiny gem, a TagHelper.
A ‘which menu has been clicked-set-active-helper’
What it does, basically, is checking if a <li> element has an attribute activecheck. If so, it detects which ‘action-route’ was executed/is executing and if the name matches, it adds class=”active”. So the output will be e.g.
<li class=”active”><a href=”/”>Home</a></li>
e.g. in the Razor View I have:
<ul class="rd-navbar-nav">
<li activecheck="true" data-menu="Index" >
<a asp-controller="Home" asp-action="Index">Home</a>
</li>
I had to add a ‘data-menu’ attribute, because Taghelpers, can not, as far as I found, parse the raw Razor Markup, when using ‘GetChildContentAsync()’ for instance, it only gets the HTML output that’s already there, without Razor markup. So, I cannot parse the child anchor and retrieve asp-acction=”Index”.
Therefore, I specify it again using data-menu=”Index”. Note, this is removed later by the taghelper.
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace ladidah.TagHelpers
{
[HtmlTargetElement("li", Attributes = "activecheck")]
public class LiActiveHelper: TagHelper
{
public bool activecheck { get; set; }
private readonly string menu;
public LiActiveHelper(IActionContextAccessor httpContext)
{
var currentRoute = (ControllerActionDescriptor)httpContext.ActionContext.ActionDescriptor;
menu = currentRoute.ActionName;
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (activecheck)
{
var dataMenu = output.Attributes["data-menu"];
if (dataMenu != null && dataMenu.Value is HtmlString str && str.Value == menu)
{
output.Attributes.RemoveAll("activecheck");
output.Attributes.RemoveAll("data-menu");
if (!output.Attributes.ContainsName("class"))
{
output.Attributes.SetAttribute("class", "active");
}
}
}
}
}
}
To activate this taghelper, I had to add the following line in my _ViewImports.cshtml file
@addTagHelper ladidah.TagHelpers.LiActiveHelper, ladidah
Benefit of IoC in ASP.NET Core.
In my ConfigureServices method, in startup.cs I had to add the following line, in order to be able to get the action context of the current MVC Controller.
public void ConfigureServices(IServiceCollection services)
{
// code removed for readability
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
I hope you find this snippet useful.