UseSimpleRendering in a SharePoint 2010 Navigation Menu

Heather Waterman and I were talking about some stuff today (Name dropper, you say? Absolutely!) and she pointed out an interesting little trick with an SharePoint:AspMenu control.

SharePoint:AspMenu controls are used in SharePoint to dynamically create navigational elements like the top navigation tabs. In SharePoint 2007, those tabs were rendered as pretty complicated TABLE constructs, and you didn’t have a lot of choice about it. Many a designer lamented this, wanting nice, clean unordered lists (UL) to work with instead.

Well, in SharePoint 2010, the navigation elements are rendered as unordered lists, just like everyone’s wanted for years. Everyone’s happy, right? Well, apparently that may not be the case because the SharePoint:AspMenu control in SharePoint 2010 now has property called UseSimpleRendering which you can use to basically revert that behavior back to the more standard ASP.NET TABLE-based elements.

By default, UseSimpleRendering is set to true in SharePoint 2010, as shown in the highlighted line below.

  <StaticMenuItemStyle CssClass="ms-topnav" ItemSpacing="0px"/>
  <StaticSelectedStyle CssClass="ms-topnavselected" />
  <StaticHoverStyle CssClass="ms-topNavHover" />
  <DynamicMenuStyle  BackColor="#fff" BorderColor="#E8E8E4" BorderWidth="1px"/>
  <DynamicMenuItemStyle CssClass="ms-topNavFlyOuts"/>
  <DynamicHoverStyle CssClass="ms-topNavFlyOutsHover"/>
  <DynamicSelectedStyle CssClass="ms-topNavFlyOutsSelected"/>

This renders markup for the top nav which looks something like this:

<DIV id=zz15_TopNavigationMenuV4 class=ms-topNavContainer>
  <DIV class="menu horizontal menu-horizontal">
    <UL class="root static">
      <LI class="static selected">
        <A accessKey=1 class="static selected menu-item" title="Home Page" href="/Pages/default.aspx">
          <SPAN class=additional-background>
            <SPAN class=menu-item-text>Home</SPAN>
            <SPAN class=ms-hidden>Currently selected</SPAN>

Don’t like that newfangled markup that everyone’s been clamoring for? Hey, switch UseSimpleRendering to false and you can go back to the bad ole days.

<TABLE id=zz1_TopNavigationMenuV4 class="ms-topNavContainer zz1_TopNavigationMenuV4_2" border=0 cellSpacing=0 cellPadding=0><TBODY>
    <TD id=zz1_TopNavigationMenuV4n0 onmouseover=Menu_HoverStatic(this) title="Home Page" onkeyup=Menu_Key(this) onmouseout=Menu_Unhover(this)>
      <TABLE class="ms-topnav zz1_TopNavigationMenuV4_4 ms-topnavselected zz1_TopNavigationMenuV4_9" border=0 cellSpacing=0 cellPadding=0 width="100%" hoverClass="zz1_TopNavigationMenuV4_13 ms-topNavHover">
            <TD style="WHITE-SPACE: nowrap">
              <A accessKey=1 style="BORDER-BOTTOM-STYLE: none; BORDER-RIGHT-STYLE: none; BORDER-TOP-STYLE: none; FONT-SIZE: 1em; BORDER-LEFT-STYLE: none" class="zz1_TopNavigationMenuV4_1 ms-topnav zz1_TopNavigationMenuV4_3 ms-topnavselected zz1_TopNavigationMenuV4_8" href="/Pages/default.aspx" hoverHyperLinkClass="zz1_TopNavigationMenuV4_12 ms-topNavHover">Home</A>

Guess what else this means. Guessed yet? No? Well, it means that there are two sets of CSS classes: one for the “simple” markup, and one for the traditional ASP.NET aproach. Be sure to keep ’em in synch if you’re switching back and forth.

Breaking .NET Habits When You Write Script

There’s a long thread over at‘s Stump the Panel where I’m trying to help someone to set up some jQuery to do some calculations in the form to check if the values are valid. The person (handles don’t always give away gender!) is struggling (IMHO) with the difference between server-side and client-side code. There’s been a lot of back and forth, but here’s some of the latest exchange, as I think it may be helpful to others.

Where we are at the moment is figuring out where the script should go in the aspx page and how to select, or find, the right values in the rendered page.

They have said that they are “Placing [the script] in the ASP: Content section”. There are lots of asp:content sections, and which one you choose can have an impact on how and when your script runs (or doesn’t run). I generally put my script right below the line:

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">

This is the most reliable place to put the script in my experience. You can also place the script in a Content Editor Web Part (CEWP).

The person has posted the snippet of code below and asked which of the values shown is the DisplayName.

  <td width="190px" valign="top">
      <nobr>Deal 5 Allocation</nobr>
  <td width="400px" valign="top">
    <SharePoint:FormField runat="server" id="ff41{$Pos}" ControlMode="Edit" FieldName="Deal_x0020_5_x0020_Allocation" __designer:bind="{ddwrt:DataBind('u',concat('ff41',$Pos),'Value','ValueChanged','ID',ddwrt:EscapeDelims(string(@ID)),'@Deal_x0020_5_x0020_Allocation')}"/>
    <SharePoint:FieldDescription runat="server" id="ff41description{$Pos}" FieldName="Deal_x0020_5_x0020_Allocation" ControlMode="Edit"/>

The problem is that this is the server-side code. The SharePoint:FormField will be rendered as HTML by SharePoint, so looking at the page server-side while the script is running client-side really doesn’t work. As I point out to folks a *lot*, you really need to get used to using the Developer Tools or Firebug or something to look at the Document Object Model (DOM) client-side to understand what is rendered rather than what controls are in the page server-side.

This is what the person keeps trying to do:

$("input[Title='ff41{$Pos}']").blur(function () {
  // whatever else you want to do... (blank out the column value, turn it red, whatever)

This won’t work, because the Title is never going to equal ‘ff41{$Pos}’ client-side. At the very least, the {$Pos} will be evaluated to the current row position, so the id will look like ‘ff411’. Instead it should be:

$("input[Title='Column 1']").blur(function () {
  // whatever else you want to do... (blank out the column value, turn it red, whatever)

The selector $(“input[Title=’Column 1′]”) says “find me an input element which has its Title attribute set to the string ‘Column 1′”. So you need to look at the input element in the DOM to see what the Title attribute contains. SharePoint always sets the Title to the DisplayName of the column for input elements, so if your column is called ‘Deal 5 Allocation’, that’s the DisplayName. ‘Deal_x0020_5_x0020_Allocation’ is the internal name, also called the StaticName. Note that the StaticName never changes after you create the column even if you change the DisplayName repeatedly.

Hope this is useful to folks out there!