views:

642

answers:

2

I'm looking to create a top-level horizontal menu, with a second-level horizontal menu below it. Clicking on the top level menu causes the second level menu to change, based on the top level one. clicking on a second level menu causes the content of the page to change.

(BTW - I'm looking to do all this in ASP.NET MVC, so if you have any insights specific to this framework, please share them).

  1. I'm not sure what's the best way to do the two-level menu, so there are zero page refreshes while the user plays with the top level menu. (CSS menu? javascript manipulating the page? a combination of both?)

  2. How do I make the app refresh/redirect/load only the bottom pane (the main content of the page), rather than the entire page? ASP.NET MVC is pretty much full-page oriented by default. Should I frame its pages?

I'm a hard-core server developer working on his first web app, so be gentle... :)

+2  A: 

Take a look at jQuery's superfish plugin

http://users.tpg.com.au/j_birch/plugins/superfish - go to Examples and nav-bar style

This works by building up a html list and uses jquery and css to style it.

<ul>
   <li><a href="">Top level item 1</a>
       <ul>
           <li><a href="">Sub item</a></li>
       </ul>
   </li>
   <li><a href="">Top level item 2</a>
       <ul>
           <li>Sub item</li>
       </ul>
   </li>
</ul>

Each item could/should relate to a controller/action method. You will then have to work out which controller/action you are viewing to make sure the correct menu item is selected for each page.

Here's a menu.ascx partial view I created.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

<% string menu = ViewContext.RouteData.Values["Controller"].ToString().ToLower(); %>
<% string submenu = ViewContext.RouteData.Values["Action"].ToString().ToLower(); %>

<div id="navigation">
    <ul id="menu" class="nav-menu nav-navbar">
        <% if (menu=="home") { %><li class="current"><% } else { %><li><% } %>
      <%= Html.ActionLink("Home", "Index", "Home") %>
   <ul></ul>
  </li>
  <% if (menu=="configuration") { %><li class="current"><% } else { %><li><% } %>
      <%= Html.ActionLink("Configuration", "Index", "Configuration") %>
   <ul>
       <% if (menu=="configuration" && submenu=="page") { %><li class="current"><% } else { %><li><% } %>
        <%= Html.ActionLink("Pages", "Pages", "Configuration") %>
    </li>
    <% if (menu=="configuration" && submenu=="headline") { %><li class="current"><% } else { %><li><% } %>
        <%= Html.ActionLink("Headlines", "Headlines", "Configuration") %>
    </li>
    <% if (menu=="configuration" && submenu=="file") { %><li class="current"><% } else { %><li><% } %>
        <%= Html.ActionLink("Files", "Files", "Configuration") %>
    </li>
    <% if (menu=="configuration" && submenu=="rules") { %><li class="current"><% } else { %><li><% } %>
        <%= Html.ActionLink("Application Rules", "Rules", "Configuration") %>
    </li>
   </ul>
  </li>
  ...
David Liddle
+3  A: 

@Shachar, you're asking 2 questions in one post, that's not the best way to use this site. :-)

I'm not sure what's the best way to do the two-level menu, so there are zero page refreshes while the user plays with the top level menu.

In my comment I have linked you to the original Suckerfish article, which has become a very common / perhaps the most common way of doing this. David Liddle showed you a more more recent implementation of Suckerfish using jQuery; if you're already using jQuery then this is IMHO the best solution today.

Since you're asking about the ASP.NET MVC angle, Syncfusion has a package of GUI widgets for ASP.NET MVC, and Telerik is building one using jQuery and community involvement. Not sure if any of them have a menu widget yet...

How do I make the app refresh/redirect/load only the bottom pane (the main content of the page), rather than the entire page? ASP.NET MVC is pretty much full-page oriented by default.

Hmn, I don't think ASP.NET MVC is "full-page oriented", there are just many different opinions on how to do AJAX. ASP.NET MVC gives you excellent building blocks for AJAX, not the full solution.

First off, are you sure you want to do this? I think what you're referring to is "AJAH", Asynchronous JavaScript And HTML. From this article about AJAH: "With true AJAX, a call is made to the server, the nicely formatted data is returned and the client application extracts the data from the xml, and replaces whatever elements need to be replaced on a page. With AJAH, a glob of html is returned and slapped into the page.".

AJAH isn't used that often today, for the following reasons:

  • You're not saving a significant amount of page weight (bytes) compared to a more conventional approach that uses caching to reduce subsequent page weights.
  • You're not separating data and presentation, so your code is less clean, and you're not building something that would be re-usable in an API or SOA approach later on.

IMHO the best use of AJAX right now, with regards to (usability improvement) versus (development and QA time) required, is to let high-ROI pages load datasets via AJAX. For example, a statistics section of a webapp might load as a normal page (with an initial dataset showing the graph the user most likely wants), and allow the user to change the graph via an AJAX call for new data.

IMHO you should also consider unobtrusive Javascript. It's kind of hard to explain, but it starts with a simple question: "What if the user agent doesn't support Javascript?". In my graph example above, the user would be out of luck, because he could not change the graph without Javascript. Here is a good presentation showing unobtrusive Javascript examples.

The other side of the coin is full-blown AJAX (like GMail), where more or less everything is built using Javascript UI widgets. This requires quite a lot of effort to build...

Assuming you want to go the AJAX route, here is one short introduction to AJAX using ASP.NET MVC and jQuery. After that, perhaps one of these books could be helpful?

Jesper Mortensen
@jesper.mortensen, I've accepted the answer by @David since it's accurate and right on the money. however, I wanted to thank you for taking the time to compose such a detailed and thoughtful answer!
Shachar