DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • Five Java Books Beginners and Professionals Should Read
  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Alpha Testing Tutorial: A Comprehensive Guide With Best Practices
  • Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices

Trending

  • Five Java Books Beginners and Professionals Should Read
  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Alpha Testing Tutorial: A Comprehensive Guide With Best Practices
  • Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices

ActiveRoute TagHelper

In this post, we'll go over creating TagHelpers using ActiveRoute, HTML, CSS, and C#, allowing you to manipulate your site's view.

Jurgen Gutsch user avatar by
Jurgen Gutsch
·
Mar. 27, 17 · Tutorial
Like (3)
Save
Tweet
Share
5.75K Views

Join the DZone community and get the full member experience.

Join For Free

i recently read a pretty cool blog post by ben cull about the isactiveroute taghelper. this taghelper adds a css class to an element if the specified route or route parts are in the current, active route. this is pretty useful if you want to highlight an active item in a menu.

inspired by this idea, i created a different taghelper, which shows or hides content, if the specified route or route parts are in the current route. this could be useful, for example, if you don't want to have a link in an active menu item.

from the perspective of a semantic web, it doesn't make sense to link to the current page. that means the menu item that points to the current page should not be a link.

the usage of this taghelper will look like this:

<ul class="nav navbar-nav">
  <li>
    <a asp-active-route asp-action="index" asp-controller="home" asp-hide-if-active="true">
      <span>home</span>
    </a>
    <span asp-active-route asp-action="index" asp-controller="home">home</span>
  </li>
  <li>
    <a asp-active-route asp-action="about" asp-controller="home" asp-hide-if-active="true">
      <span>about</span>
    </a>
    <span asp-active-route asp-action="about" asp-controller="home">about</span>
  </li>
  <li>
    <a asp-active-route asp-action="contact" asp-controller="home" asp-hide-if-active="true">
      <span>contact</span>
    </a>
    <span asp-active-route asp-action="contact" asp-controller="home">contact</span>
  </li>
</ul>

as you may see on the a-tag, multiple taghelpers can work on a single tag. in this case, the built-in anchortaghelper and the activeroutetaghelper are manipulating the tag. the a-tag will be hidden if the specified route is active and the span-tag is shown in that case.

if you now navigate to the about page, the a-tag is removed from the specific menu item and the span-tag is shown. the html result of the menu now looks pretty clean:

<ul class="nav navbar-nav">
  <li>
    <a href="/">
      <span>home</span>
    </a>
  </li>
  <li>
    <span>about</span>
  </li>
  <li>
    <a href="/home/about">
      <span>contact</span>
    </a>
  </li>
</ul>

using this approach for the menu, we don't need ben culls taghelper here to add a special css class. the style for the active item can be set via the selection of that list item with just the span in it:

.nav.navbar-nav li > a { ... }
.nav.navbar-nav li > a > span { ... }
.nav.navbar-nav li > span { ... } /* this is the active item*/

this css is based on the default bootstrap based template in a new asp.net core project. if you use another template, just replace the css class which identifies the menu with your specific identifier.

that means, to get that active menu item looking nice, you may just add some css like this:

.navbar-nav li > span {
    padding: 15px;
    display: block;
    color: white;
}

this results in the following view:

to get this working, we need to implement the taghelper. i just created a new class in the project and called it activeroutetaghelper and added the needed properties:

[htmltargetelement(attributes = "asp-active-route")]
public class activeroutetaghelper : taghelper
{
  [htmlattributename("asp-controller")]
  public string controller { get; set; }

  [htmlattributename("asp-action")]
  public string action { get; set; }

  [htmlattributename("asp-hide-if-active")]
  public bool hideifactive { get; set; }


}

that class inherits the taghelper base class. to use it on any html tag, i defined an attribute name which is needed in the html we want to manipulate. i used the name "asp-active-route". also, the attribute gets a specific name. i could use the default name, without the leading "asp" prefix, but i thought it would make sense to share the controller and action properties with the built-in anchortaghelper. and to be consistent, i use the prefix in all cases.

now we need to override the process method to actually manipulate the specific html tag:

public override void process(taghelpercontext context, taghelperoutput output)
{
  if (!canshow())
  {
    output.suppressoutput();
  }

  var attribute = output.attributes.first(x => x.name == "asp-active-route");
  output.attributes.remove(attribute);
}

if i cannot show the tag because of the conditions in the cahshow() method, i completely suppress the output. nothing is generated in that case. not the contents and not the html tag itself.

at the end of the method, i remove the identifying attribute, which is used to activate this taghelper, because this attribute will usually be kept.

to get the routedata of the current route, we can't use the taghelpercontext or the taghelperoutput. we need to add the inject to the viewcontext:

[htmlattributenotbound]
[viewcontext]
public viewcontext viewcontext { get; set; }

now we are able to access the route data and get the needed information about the current route:

private bool canshow()
{
  var currentcontroller = viewcontext.routedata.values["controller"].tostring();
  var currentaction = viewcontext.routedata.values["action"].tostring();

  var show = false;
  if (!string.isnullorwhitespace(controller) &&
      controller.equals(currentcontroller, stringcomparison.currentcultureignorecase))
  {
    show = true;
  }
  if (show &&
      !string.isnullorwhitespace(action) &&
      action.equals(currentaction, stringcomparison.currentcultureignorecase))
  {
    show = true;
  }
  else
  {
    show = false;
  }

  if (hideifactive)
  {
    show = !show;
  }

  return show;
}

one last step you need to do is to register your own taghelpers. in visual studio, open the _viewimports.cshtml and add the following line of code:

@addtaghelper *, corewebapplication 

where corewebapplication is the assembly name of your project, * means use all taghelpers in that library.

conclusion

i hope this makes sense to you and helps you a little more to get into using taghelpers.

i always have fun creating a new taghelper. with less code, i'm able to extend the view engine the way i need.

i always focus on semantic html, if possible, because it makes the web a little more accessible to other devices and engines than we usually use. this could be screen readers for blind people, as well as search engines. maybe i can do some more posts about accessibility in asp.net core applications.

ASP.NET Core Attribute (computing) Links Engine Template Semantics (computer science) POST (HTTP) Property (programming)

Published at DZone with permission of Jurgen Gutsch. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Five Java Books Beginners and Professionals Should Read
  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Alpha Testing Tutorial: A Comprehensive Guide With Best Practices
  • Cypress Tutorial: A Comprehensive Guide With Examples and Best Practices

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: