Reputation: 47407
I'm looking at the StackOverflow website and I've noticed that there is a Class="youarehere"
attribute set to the buttons of active views. This results in the orange styling instead of the grey styling.
Can anybody tell me how they're doing this? What's the easiest way to dynamically set the class based on the URL?
Upvotes: 3
Views: 7952
Reputation: 246
you could create a HtmlHelper to return the value, that way you can use it anywhere
Create a “HtmlHelpers” folder in your project Create a static class Define a static method with the first parameter “this HtmlHelper helper“
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
namespace ThisMVCApp.WebUI.HtmlHelpers
{
public static class HtmlHelperExtensions
{
public static string IfActive(this HtmlHelper helper, string controller, string action)
{
string classValue = "";
string currentController = helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
string currentAction = helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
if (currentController == controller && currentAction == action)
{
classValue = "youarehere";
}
return classValue;
}
}
}
Add this to your web.config file (the one in your Views folder!!)
<system.web.webPages.razor>
<host ... />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
...
<add namespace="ThisMVCApp.WebUI.HtmlHelpers" />
</namespaces>
</pages>
</system.web.webPages.razor>
now you can just apply the above method as any class or attribute on buttons or any element like so :
<nav>
<ul id="menu">
<li class="@Html.IfActive("Home", "Index")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@Html.IfActive("Home", "About")">@Html.ActionLink("About", "About", "Home")</li>
</ul>
</nav>
Upvotes: 0
Reputation: 47407
Here's the answer I needed (In VB) Thanks @Darin
Imports System.Web.Mvc
Imports System.Web.Mvc.Html
Namespace Utilities.HtmlHelpers
Public Module PagingHelpers
Sub New()
End Sub
<System.Runtime.CompilerServices.Extension()> _
Public Function CustomLink( _
ByVal htmlHelper As HtmlHelper, _
ByVal linkText As String, _
ByVal actionName As String, _
ByVal controllerName As String) As MvcHtmlString
Dim currentAction As String = TryCast(htmlHelper.ViewContext.RouteData.Values.Item("action"), String)
Dim currentController As String = TryCast(htmlHelper.ViewContext.RouteData.Values.Item("controller"), String)
If ((actionName = currentAction) AndAlso _
(controllerName = currentController)) Or _
((controllerName = currentController) AndAlso _
Not controllerName = "Events") Then
Return htmlHelper.ActionLink( _
linkText, _
actionName, _
controllerName, _
Nothing, _
New With { _
.class = "youarehere" _
})
End If
Return htmlHelper.ActionLink(linkText, actionName, controllerName)
End Function
End Module
End Namespace
Upvotes: 0
Reputation: 1546
I have an alternative solution. Rather than having the helper class decide which "menu" is the active menu. Decide that in your controller's action.
Your Controller
public ActionView Questions()
{
MyViewModel model = new MyViewModel ();
model.CurrentMenu = "Questions";
ViewData.Model = model;
}
public ActionView Tags()
{
MyViewModel model = new MyViewModel ();
model.CurrentMenu = "Tags";
ViewData.Model = model;
}
In the View (a strongly typed view)
<div id="menu">
<ul>
<li class="<%= Html.IsSelectedMenu(Model.CurrentMenu,'Questions') %>"<a href="/Home/Questions">Questions</a></li>
<li class="<%= Html.IsSelectedMenu(Model.CurrentMenu,'Tags') %>"<a href="/Home/Tags">Tags</a></li>
</ul>
</div>
In your css
li.youarehere
{
background-color: orange;
color: #ffffff;
}
In your helper class
public static class MyHtmlExtensions
{
public static MvcHtmlString IsSelectedMenu(this HtmlHelper helper, string currentMenu, string menu2)
{
return currentMenu.Equals (menu2)? "youarehere" : "";
}
}
Upvotes: 0
Reputation: 1039160
Writing an html helper for those buttons could be one way of doing it. Assuming the standard routing is set:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
here's how the helper might look like:
public static MvcHtmlString MyButton(this HtmlHelper htmlHelper, string id, string text)
{
var button = new TagBuilder("input");
button.MergeAttribute("type", "button");
button.MergeAttribute("value", text);
// get the id from the current route:
var routeId = htmlHelper.ViewContext.RouteData.Values["id"] as string;
if (id == routeId)
{
button.MergeAttribute("class", "active");
}
return MvcHtmlString.Create(button.ToString(TagRenderMode.SelfClosing));
}
and finally add to your view:
<%= Html.MyButton("questions", "Questions") %>
<%= Html.MyButton("tags", "Tags") %>
<%= Html.MyButton("users", "Users") %>
To further improve the helper you could add additional parameters that will contain the action and the controller this button will redirect to when clicked.
Upvotes: 5
Reputation: 40202
I would assume the simplest possible way is to place the information in the ViewData from the controller/action telling the view where it is, which is what I do.
In the view, you would get that data from the ViewData, then figure out which class name to associate to which location. Be sure to use an HTML Helper.
Action under Questions controller:
public ActionResult Index()
{
ViewData["CurrentPage"] = "Questions";
}
Html Helper:
public static string GetLocationCssClassName(this HtmlHelper html)
{
string cssClass = string.Empty;
if(html.ViewData["CurrentPage"] != null)
{
string currentPage = (string)html.ViewData["CurrentPage"];
switch(currentPage)
{
case "Questions":
cssClass = "question_css_class";
break;
case "Tags":
cssClass = "tags_css_class";
break;
case "Users":
cssClass = "users_css_class";
break;
}
}
return cssClass;
}
View Page:
<div id="main" class="<%: Html.GetLocationCssClassName() %>">
<a href="Questions/Index" class="questions">Questions</a>
<a href="Tags/Index" class="tags">Tags</a>
<a href="Users/Index" class="users">Users</a>
</div>
Css:
.question_css_class a.questions
{
background-color: Orange;
}
The code can be improved endlessly, but you get the gist. Your view has access to ViewData. Designate a specific key that will hold the current page and output the proper class based on the value inside that specific key.
Upvotes: 0