How to add an attribute to an HTML tag depending on the URL in a MVC app

I render a list of items like:

<ul>
  <li>Something 1</li>
  <li>Something 2</li>
  <li>Something 3</li>
  <li>Something 4</li>
  <li>Something 5</li>
</ul>

Depending on the route I want to add a class to one of the <li> tags so that I can highlight.

Maybe something like:

<ul>
<% if (this.Context.Request.RawUrl.Contains(something1Var)) { %>
<li class="highlight">
<% } else { <%>
<li>
<% } %>
Something 1</li>

<% if (this.Context.Request.RawUrl.Contains(something2Var)) { %>
<li class="highlight">
<% } else { <%>
<li>
<% } %>
Something 2</li>

<% if (this.Context.Request.RawUrl.Contains(something3Var)) { %>
<li class="highlight">
<% } else { <%>
<li>
<% } %>
Something 3</li>
<% if (this.Context.Request.RawUrl.Contains(something3Var)) { %>
<li class="highlight">
<% } else { <%>
<li>
<% } %>
Something 4</li>

<% if (this.Context.Request.RawUrl.Contains(something5Var)) { %>
<li class="highlight">
<% } else { <%>
<li>
<% } %>
Something 5</li>
</ul>

It does work but it seems a bit verbose. Can anyone suggest a better method of doing this sort of thing?

13.10.2009 20:00:08
+1 Because this is the most common menu behaviour and it does seem obscured in MVC.
Robert Koritnik 13.10.2009 21:44:40
1 ОТВЕТ
РЕШЕНИЕ

I'd argue that this kind of logic is better isolated in the controller. Consider making a lightweight class to represent your menu items, like this:

public class MenuLinkItem {
    public string Text { get; set; }
    public bool Highlight { get; set; }
}

Then in your controller method, build a list of these, set the CSS class on the highlighted element, and pass the result to the view via the ViewData:

public class MyController : Controller { 
  private MenuLinkItem MakeMenuLinkItem(string text, string urlFragment) {
     return (new MenuLinkItem() {
        Text = text,
        Highlight = (this.Context.Request.RawUrl.Contains(urlFragment))
     }
  }   

  private IList<MenuLinkItem> GetMenuLinkItems() {
      var items = new List<MenuLinkItem>();  

     items.Add(MakeMenuLinkItem("Something 1", something1var));
     items.Add(MakeMenuLinkItem("Something 2", something2var));
     items.Add(MakeMenuLinkItem("Something 3", something3var));
     items.Add(MakeMenuLinkItem("Something 4", something4var));
     items.Add(MakeMenuLinkItem("Something 5", something5var));
     return(items);
  }

  public ActionResult Index() {
      ViewData["menuLinkItems"] = GetMenuLinkItems();
      /* other controller logic here */
      return(View());
  }
}

Then, in your actual view code, you render your menu like this:

<ul>
<% foreach(var item in (IList<LinkMenuItem>)ViewData["menuLinkItems"])) { %>
  <li <%= item.Highlight ? "class=\"highlight\"" : ""%>><%=item.Text%></li>
<% } %>
</ul>

The controller's making the decisions about which links are highlighted, and the view is converting those decisions into an HTML/CSS representation that makes sense to your users.

4
13.10.2009 20:15:08
Great solution. I like the idea of keep this sort of logic in the controller and keeping the view as simple as possible. Thanks
littlechris 14.10.2009 13:07:19