first off some background. i have a web site written in MVC5 and VS 2013. i created the project using the MVC template so i do have the bootstrap navbar at the top which is where all my menu links are. each link corresponds to a different view and each view uses (by default) _Layout.cshtml. i want to do 2 things to the links on the navbar - 1. have the current selected (active) item highlited when selected and 2. have them ajax compliant so that only the content of each view is refreshed not the entire page when a link is clicked. i already have goal 1 done and working but i'm not sure i'm doing it right. after finding a sample on the web i created an html helper extension method in the App_Code directory that looks like this..
public static class MyHelper
{
public static MvcHtmlString HtmlLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName)
{
var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
var builder = new TagBuilder("li")
{
InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToHtmlString()
};
if (controllerName == currentController && actionName == currentAction)
builder.AddCssClass("active");
return new MvcHtmlString(builder.ToString());
}
}
i implemented it in _Layout like this..
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.HtmlLink("Home", "Index", "Home")</li>
<li>@Html.HtmlLink("About Me", "AboutMe", "Home")</li>
<li>@Html.HtmlLink("Samples", "Samples", "Home")</li>
<li>@Html.HtmlLink("Links", "Links", "Home")</li>
<li>@Html.HtmlLink("Contact", "Contact", "Home")</li>
</ul>
@*@Html.Partial("_LoginPartial")*@
</div>
the only question i have with this is how does VS know that HtmlLink is a helper extension? i didn't inherit from anything and both the class and method names were ones i made up. all i had to do was put @Html in front and it knew what it was. just want to understand whats going on. sure it works but i want to know why.
now for the Ajax stuff. i got that working also but i had to change the html helper calls in _Layout to ajax helper calls as so..
<li>@Ajax.ActionLink("Home", "Index", "Home", new AjaxOptions() { UpdateTargetId = "site_content" })</li>
<li>@Ajax.ActionLink("About Me", "AboutMe", "Home", new AjaxOptions() { UpdateTargetId = "site_content" })</li>
<li>@Ajax.ActionLink("Samples", "Samples", "Home", new AjaxOptions() { UpdateTargetId = "site_content" })</li>
<li>@Ajax.ActionLink("Links", "Links", "Home", new AjaxOptions() { UpdateTargetId = "site_content" })</li>
<li>@Ajax.ActionLink("Contact", "Contact", "Home", new AjaxOptions() { UpdateTargetId = "site_content" })</li>
but now i'm in a quandary. since in both cases i had to change the same code in _Layout, i can right now only do one or the other not both. is there a way to possibly combine the 2 functionalities into one helper method or maybe there's a better way to do either or both? appreciate any help.
surprised nobody came up with this. the first question was answered but the second was not. to reiterate, it was 'how do i get both the active menu selection and Ajax to work at the same time using extensions?' took some doing but i found the answer. i ended up using the Ajax.ActionLink helper in _Layout.cshtml to implement Ajax and the following jquery added to each view to implement the menu selection. very simple and ended up not even needing the extension..
$(document).ready(function () {
$('ul.nav.navbar-nav').find('a[href="' + location.pathname + '"]')
.closest('li').addClass('active');
});
so as it turns out i didn't need the Html helper extension method i created but at least i learned how to do it. anyway, to finish things off, i just changed the default attributes in bootstrap.css to fit my preferences and that was it..
.navbar-inverse .navbar-nav > .active > a,
.navbar-inverse .navbar-nav > .active > a:hover,
.navbar-inverse .navbar-nav > .active > a:focus {
color: #DA9C9C;
background-color: #FFFFFF; /**/
text-shadow: 0px 0px #FFFFFF; /**/
font-weight:bold;
}
both objectives are now met and it works like a champ.