views:

256

answers:

4

After looking at how the Orange Tabs ASP.NET MVC demo handles tabs, they have something like:

View:

<ul id="menu">
            <% if (Html.IsCurrentAction("Index", "Home")) { %>
                <li class="active"><%= Html.ActionLink("Home", "Index", "Home")%></li>
            <% } else { %>
                <li><%= Html.ActionLink("Home", "Index", "Home") %></li>
            <% }%>

            <% if (Html.IsCurrentAction("About", "Home"))
               { %>
                <li class="active"><%= Html.ActionLink("About", "About", "Home")%></li>
            <% } else { %>
                <li><%= Html.ActionLink("About", "About", "Home")%></li>
            <% }%>

            <% if (Html.IsCurrentAction("SampleTags", "Home"))
               { %>
                <li class="active"><%= Html.ActionLink("Sample Tags", "SampleTags", "Home")%></li>
            <% } else { %>
                <li><%= Html.ActionLink("Sample Tags", "SampleTags", "Home")%></li>
            <% }%>
            </ul>

and a corresponding helper class:

namespace Helpers
{
    public static class IsCurrentActionHelper
    {
        public static bool IsCurrentAction(this HtmlHelper helper, string actionName, string controllerName)
        {
            string currentControllerName = (string)helper.ViewContext.RouteData.Values["controller"];
            string currentActionName = (string)helper.ViewContext.RouteData.Values["action"];

            if (currentControllerName.Equals(controllerName, StringComparison.CurrentCultureIgnoreCase) && currentActionName.Equals(actionName, StringComparison.CurrentCultureIgnoreCase))
                return true;

            return false;
        }
    }
}

Does this seem like an elegant way to approach this problem? I've seen dozens of different ways from javascript to query strings, etc.

I don't like javascript because I want the website to be fine for non-js enabled browsers and the query string approach seems cludgey.

+5  A: 
<% if (Html.IsCurrentAction("Index", "Home")) { %>
     <li class="active"><%= Html.ActionLink("Home", "Index", "Home")%></li>
<% } else { %>
     <li><%= Html.ActionLink("Home", "Index", "Home") %></li>
<% }%>

I'd hide all this behind a helper method:

<%= Html.Activelink("Index", "Home", "Home") %>
Talljoe
A: 

Either wrap it in a helper as suggested, or do something like I describe in this answer.

John Sheehan
A: 

The most elegant solution I've ever seen was done by Torkel Ödegaard over at http://www.codinginstinct.com/ using ViewModel inheritance. It includes a great fluent interface for adding/manipulating tabs.

Now his view code is using the Spark view engine but you could easily implement it in the WebForm view engine.

http://www.codinginstinct.com/2008/10/view-model-inheritance.html

Chad Moran
+2  A: 

If you create an object to define the menustructure the markup can easily be generated by a ViewUserControl which would make it easier to reuse in multiple places with a single line (substitute your preferred presistence mechanism).

<% Html.RenderPartial("Tabs", Session[Consts.cAdminTabSet]); %>

Here is a class that I used to define the tabs.

public class TabSet
{
    public string ContainerID {get;set;}
    public List<TabDefinition> Tabs { get; set; }
    public string activeTab { get; set; }
}

public class TabDefinition
{
    public string Name { get; set; }
    public string Title { get; set; }
    public string HRef { get; set; }
    public string Img { get; set; }
    public bool ShowText { get; set; }
    public string CSSClass { get; set; }
}

and here is the ViewUserControl used to render the tabs:

<%@ Control Language="C#" 
 Inherits="System.Web.Mvc.ViewUserControl<TabSet>" %>
<% if (Model != null && !Model.Collapsed)
   { %>
    <div id="<%=  Model.ContainerID %>">
        <ul>
        <% foreach (var tb in Model.Tabs)
           {%>
               <li class="<%= (tb.Name == Model.activeTab)? "selected": "" %> <%= (string.IsNullOrEmpty(tb.CSSClass)) ? "" : tb.CSSClass  %>">

                    <a title="<%= tb.Title %>" href="<%= tb.HRef %>">
                    <span><% if (!string.IsNullOrEmpty(tb.Img)){%><img alt="<%= tb.Name %>" src="<%= tb.Img %>" /><%} %>
                    <% if (string.IsNullOrEmpty(tb.Img) || tb.ShowText == true){%><%= tb.Name%><%} %></span></a>
                </li>
           <%} %>
        </ul>
    </div>
<%} %>

Here is the CSS I used.

#lvl3Tab
{
    float: left;
    width: 100%;
    background: #C50000;
    font-size: 93%;
    line-height: normal;
    /*border-bottom: 1px solid #666;*/
}
#lvl3Tab img
{
    border: none;
    padding: 0px;
    margin: 0px;
}

#lvl3Tab ul
{
    margin: 0;
    padding: 5px 10px 0 50px;
    list-style: none;
}
#lvl3Tab li
{
    display: inline;
    margin: 0;
    padding: 0;
}
#lvl3Tab a
{
    float: left;
    background: url("/images/tableftM.gif") no-repeat left top;
    margin: 0;
    padding: 0 0 0 4px;
    text-decoration: none;
}
#lvl3Tab a span
{
    float: left;
    display: block;
    background: url("/images/tabrightM.gif") no-repeat right top;
    padding: 5px 15px 4px 6px;
    color: #666;
}
/* Commented Backslash Hack hides rule from IE5-Mac \*/
#lvl3Tab a span
{
    float: none;
    color: #fff;
}
/* End IE5-Mac hack */
#lvl3Tab a:hover span
{
    color: #FFF;
}
#lvl3Tab a:hover
{
    background-position: 0% -42px;
}
#lvl3Tab a:hover span
{
    background-position: 100% -42px;
    color:#666;
}
#lvl3Tab ul li.selected a
{
    background-position: 0% -42px;
}
#lvl3Tab ul li.selected a span
{
    background-position: 100% -42px;
    color: #666;
}
RonnBlack