Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Kris Anderson 12 posts 32 karma points
    Jan 23, 2011 @ 08:37
    Kris Anderson
    0

    Need help with sub-navigation XSLT

    Hey everyone,

    I'm still new to Umbraco and don't fully understand XSLT yet, so I'm having trouble getting my sub-navigation working.

    I have my sub-navigation working in a single level, but I want to be able to drill down another level when needed. I basically want to be able to add a <ul class="lv2"> HTML tag within my current <ul class="lv1"> tag and then style that with CSS so it looks like a sub level of the currently selected level.

    To better explain, my sub-navigation looks like this:

    Some Topic
    Another Topic
    Third Topic

    But when "Another Topic" is selected, I want it to look like is:

    Some Topic
    Another Topic
       Something Here
       Another Something
    Third topic

    I know how to do this in HTML and CSS, I'm just not sure how to get there in XLST. Here is my current SubNavigation.xlst file:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
    <xsl:stylesheet
      version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxml="urn:schemas-microsoft-com:xslt"
      xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:BlogLibrary="urn:BlogLibrary" xmlns:PS.XSLTsearch="urn:PS.XSLTsearch"
      exclude-result-prefixes="msxml
    umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes
    Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings
    Exslt.ExsltSets tagsLib BlogLibrary PS.XSLTsearch "
    >

    <xsl:output method="xml" omit-xml-declaration="yes" />

    <xsl:param name="currentPage"/>

    <!-- Input the documenttype you want here -->
    <xsl:variable name="level" select="2"/>

    <xsl:template match="/">

    <!-- The fun starts here -->
    <ul class="lv1">
      <xsl:variable name="mainNavPage" select="$currentPage/ancestor-or-self::* [@level=$level]"/>
      <li>
        <xsl:if test="$currentPage/@id = $mainNavPage/@id">
          <xsl:attribute name="class">selected</xsl:attribute>
        </xsl:if>
    <xsl:if test="string($mainNavPage/@id) != ''">
    <a href="{umbraco.library:NiceUrl($mainNavPage/@id)}/">
          <xsl:if test="$currentPage/@id = $mainNavPage/@id">
          <xsl:attribute name="class">selected</xsl:attribute>
        </xsl:if>
      <strong>
        <xsl:value-of select="$mainNavPage/@nodeName"/>
      </strong>
      <xsl:value-of select="$mainNavPage/navigationDescription" />
    </a>
    </xsl:if>

      </li>

    <xsl:for-each select="$currentPage/ancestor-or-self::* [@level=$level]/* [@isDoc and string(umbracoNaviHide) != '1']">
      <li>
        <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
          <xsl:attribute name="class">selected</xsl:attribute>
        </xsl:if>
        <a>
          <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
            <xsl:attribute name="class">selected</xsl:attribute>
          </xsl:if>
    <xsl:attribute name="href">
      <xsl:choose>
        <xsl:when test="string(displayAsDirectory) = '1'">
          <xsl:value-of select="concat(umbraco.library:NiceUrl(@id), '/')" />
        </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="concat(umbraco.library:NiceUrl(@id), '.aspx')" />       
          </xsl:otherwise>
      </xsl:choose>
    </xsl:attribute>
          <strong>
            <xsl:value-of select="@pageName" />
            <xsl:value-of select="@nodeName" />
          </strong>
          <xsl:value-of select="navigationDescription" />
        </a>
      </li>
    </xsl:for-each>
    </ul>

    </xsl:template>
    </xsl:stylesheet>

    I know the code I have to insert needs to go towards the end of that XSLT file before the following:

    </xsl:for-each>
    </ul>

    </xsl:template>
    </xsl:stylesheet>

    I've been playing around with this for a while now and I have the following code working:

      <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
      <xsl:for-each select="$currentPage/* [@isDoc and string(umbracoNaviHide) != '1']">
        <ul class="lv2">
          <li>
            <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
              <xsl:attribute name="class">selected</xsl:attribute>
            </xsl:if>
            <a href="{umbraco.library:NiceUrl(@id)}">
              <strong><xsl:value-of select="@nodeName"/></strong>
            </a>
          </li>
        </ul>
      </xsl:for-each>
      </xsl:if>

    The above code actually works when I'm viewing a 2nd level page. If a second level page is selected and it has 3rd level children below it, all of those child links show in the navigation. Works perfect right... just how I want it to. However, once I click on one of those 3rd level links, the navigation goes back to only showing 2 levels (when I want it to keep showing 3 levels). I would like to have my second level marked with class="selected", and also do the same for the third level. The problem is, the third level no longer shows.

    I know why this is happening. It's because I'm using that XSL IF statement. When I am on a third level page and this SubNavigation.xslt file is called, it finds my if statement and says there are no children. Therefor, no 3rd level pages are being shown.

    <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">

    I probably just need one line of code to get this working... but I'm not sure what I can try. Can someone help point me in the right direction?

  • Daniel Bardi 927 posts 2562 karma points
    Jan 23, 2011 @ 09:26
    Daniel Bardi
    0

    Check if the current page equal to the navigation item

    <xsl:for-each .... >

    <xsl:if test="$currentPage/@id = current()/@id>

    ... show sub navigation ...

    </xsl:if>

    </xsl:for-each>

  • Daniel Bardi 927 posts 2562 karma points
    Jan 23, 2011 @ 09:27
    Daniel Bardi
    0

    Nevermind.. didn't read the entire post.

    Sorry!

  • Kris Anderson 12 posts 32 karma points
    Jan 23, 2011 @ 10:45
    Kris Anderson
    0

    I think I finally have this working. I downloaded some demo Umbraco sites and found a Koiak Standard Site that did the sub-navigation similar to what I wanted. I took their two lines of IF statements and modified it to suite my needs. This is the code I ended up with:

        <xsl:if test="current()/@level &lt; (6) and $currentPage/ancestor-or-self::*[@isDoc]/@id = current()/@id">
          <xsl:if test="count(*[@isDoc][not(data[@alias='umbracoNaviHide']=1)]) > 0">
            <ul class="lv2">
              <xsl:for-each select="*[@isDoc][not(data[@alias='umbracoNaviHide']=1)]">
                <li>
                  <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
                    <xsl:attribute name="class">selected</xsl:attribute>
                  </xsl:if>
                  <a href="{umbraco.library:NiceUrl(@id)}">
                    <xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id">
                      <xsl:attribute name="class">selected</xsl:attribute>
                    </xsl:if>
                    <strong>
                      <xsl:value-of select="@nodeName"/>
                    </strong>
                  </a>
                </li>
              </xsl:for-each>
            </ul>
          </xsl:if>
        </xsl:if>

    Question though... is that the best way to do this? It appears to be working perfectly... but I'm not sure if there's a better way to be doing it. The two lines of code from the Koiak demo site that got this working for me were:

    <xsl:if test="current()/@level &lt; (6) and $currentPage/ancestor-or-self::*[@isDoc]/@id = current()/@id">
    <xsl:if test="count(*[@isDoc][not(data[@alias='umbracoNaviHide']=1)]) > 0">
  • Kim Andersen 1447 posts 2196 karma points MVP
    Jan 23, 2011 @ 13:34
    Kim Andersen
    0

    Hi Kris

    Often when I need a small and simple submenu eg. in a sidebar or something like that, I tend to use this piece of code:

    <xsl:variable name="rootNode" select="$currentPage/ancestor-or-self::*[@level=2]" />
    <xsl:template match="/">
    <h3 class="subMenuHeader">
    <a href="{umbraco.library:NiceUrl($rootNode/@id)}">
    <xsl:value-of select="$currentPage/ancestor-or-self::*[@level = '2']/@nodeName"/>
    </a>
    </h3>
    <ul id="subMenu">
    <xsl:apply-templates select="$rootNode/*[@isDoc and string(umbracoNaviHide) != '1']"/>
    <li class="hide">
    <p>&nbsp;</p>
    </li>
    </ul>
    </xsl:template>

    <xsl:template match="*[@isDoc and string(umbracoNaviHide) != '1']">
    <xsl:variable name="id" select="id" />
    <li class="subNiveau">
    <xsl:attribute name="class">subNiveau<xsl:if test="$currentPage/ancestor-or-self::*/@id = current()/@id"> current</xsl:if></xsl:attribute>
    <a href="{umbraco.library:NiceUrl(./@id)}">
    <xsl:value-of select="@nodeName" />
    </a>
    </li>
    <xsl:if test="count(./*[@isDoc and string(umbracoNaviHide) != '1']) &gt; 0 and count(descendant-or-self::*[@id = $currentPage/@id]) &gt; 0">
    <li class="subMenu2">
    <ul>
    <xsl:apply-templates select="./*[@isDoc and string(umbracoNaviHide) != '1']" />
    </ul>
    </li>
    </xsl:if>
    </xsl:template>

    What the above code does is of course to render a submenu. In the top of the menu, there's a link to the "main-menu-page". Of course this can be removed easily. The code will continue to add additional levels of nodes if they are present in the content tree.

    I don't know if this can inspire you, but now you've got the code for a quite easy submenu macro. Take it or leave it :)

    /Kim A

Please Sign in or register to post replies

Write your reply to:

Draft