Search code examples
htmlajaxtwitter-bootstraphtml-helper

2 interlocking questions regarding html helpers


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.


Solution

  • 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.