Copied to clipboard

Flag this post as spam?

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


  • Mike 62 posts 274 karma points
    Jan 14, 2010 @ 00:30
    Mike
    0

    Persisting the last set of menus in a sub-nav

    Hi all,

    I suspect there is a fairly straightforward answer to this question but my knowledge of XSLT is currently limited at best.

    I've set up a sub-navigation menu using an XSLT template based on "List Sub Page From Current Page" which happily displays child pages based on whatever page I'm in at the time, however, it obviously show no sub-pages in the sub-navigation (i.e. an empty nav) when there aren't any.

    Can anyone tell me how I persist the last set of menus in the sub-nav when there are no new ones to display?

    So taking an example site structure like this:

    • Parent Page 1
      • Child Sub-Page 1
        • Child Sub-Page A
        • Child Sub-Page B
        • Child Sub-Page C
      • Child Sub-Page 2
    • Parent Page 2

    What I'd like to do is when the user clicks on Child Sub-Page A, B or C the sub-menu persists to show Sub-Pages A, B and C rather than not show anything.

    In reality my site structure varies from 2 levels to 5 levels deep so the last set of menus in any given page would vary in level.

    Many thanks,

    Mike

  • Petr Snobelt 923 posts 1535 karma points
    Jan 14, 2010 @ 00:48
    Petr Snobelt
    0

    Create variable menu_source and use it instead of currentpage in menu xslt foreach block.

    Sample (typed from head):

    <xsl:variable name="menu_source">
      <xsl:choose>
        <xsl:when test="count($curentPage/node) != 0">
          <xsl:copy-of select="$currentPage" />
        <xsl:when>
        <xsl:otherwise>
          <xsl:copy-of select="$currentPage/.." />
        </xsl:otherwise>
    </xsl:variable>

    It should work, after you knowledge of xslt increase, you can try select first node with childs recursively
    (hint: http://forum.umbraco.org/yaf_postst2751_XSLT-Tip--Display-a-field-recursively.aspx)

    Petr

  • Mike 62 posts 274 karma points
    Jan 14, 2010 @ 02:59
    Mike
    0

    Hi Petr, many thanks for the reply. Could I ask you to elaborate a little more in terms of where within the XSLT "for-each" statement your code would be placed? 

    Would it sit within the existing "for-each" statement, or replace it entirely. I've tried both plus a few variants and nothing has altered the menu's behaviour yet.

    I've tweaked your code a fraction just to correct a couple of errors:

    <xsl:variable name="menu_source">
     <xsl:choose>
      <xsl:when test="count($currentPage/node) != 0">
       <xsl:copy-of select="$currentPage" />
      </xsl:when>
      <xsl:otherwise>
       <xsl:copy-of select="$currentPage/.." />
      </xsl:otherwise>
     </xsl:choose>
    </xsl:variable>

    Thank you in advance,

    Mike

  • Mike 62 posts 274 karma points
    Jan 15, 2010 @ 17:29
    Mike
    0

    Is anyone able to help me solve this issue?

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jan 15, 2010 @ 18:10
    Lee Kelleher
    0

    Hi Mike,

    Would you be able to post your XSLT?  We should be able to help by example.

    Thanks, Lee.

  • Mike 62 posts 274 karma points
    Jan 15, 2010 @ 19:45
    Mike
    0

    Hello Lee,

    Here is the full source for the XSLT page currently running my sub nav. I have left the original source in (but commented out) so you can see - it is basically out-of-the-box but with Petr's suggestion above included. The result with this code is the same as before - i.e. when it reaches the end of the structure with no more children to display it basically shows nothing rather than the last set of menus.

    <?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"
     exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">

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

    <xsl:param name="currentPage"/>

    <xsl:template match="/">

    <!-- The fun starts here -->

    <xsl:for-each select="$currentPage/node [string(data [@alias='umbracoNaviHide']) != '1']">
     <a href="{umbraco.library:NiceUrl(@id)}">

      <xsl:variable name="menu_source">
       <xsl:choose>
        <xsl:when test="count($currentPage/node) != 0">
         <xsl:copy-of select="$currentPage" />
        </xsl:when>
        <xsl:otherwise>
         <xsl:copy-of select="$currentPage/.." />
        </xsl:otherwise>
       </xsl:choose>
      </xsl:variable>
      <xsl:value-of select="@nodeName"/>

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

    <!-- ORIGINAL SOURCE
    <xsl:for-each select="$currentPage/node [string(data [@alias='umbracoNaviHide']) != '1']">
     <a href="{umbraco.library:NiceUrl(@id)}">
      <xsl:if test="$currentPage/ancestor-or-self::node/@id = current()/@id">
       < ! - - we're under the item - you can do your own styling here - - >
       <xsl:attribute name="style">
        background: #990000;
        border: 1px solid #fff;
       </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="@nodeName"/>
     </a>
    </xsl:for-each>
    -->

    </xsl:template>

    </xsl:stylesheet>

    Any guidance would be hugely appreciated.

    Best wishes,

    Mike

  • Lee Kelleher 4020 posts 15802 karma points MVP 13x admin c-trib
    Jan 15, 2010 @ 20:15
    Lee Kelleher
    0

    Hi Mike,

    Following on from Petr's suggestion, the following XSLT should work:

    <?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"
        exclude-result-prefixes="msxml umbraco.library">
        <xsl:output method="xml" omit-xml-declaration="yes" />
    
        <xsl:param name="currentPage"/>
    
        <xsl:template match="/">
    
            <xsl:variable name="menuSource">
                <xsl:choose>
                    <!-- if the current page is the root node (as in homepage) - use the current node -->
                    <xsl:when test="$currentPage/@level = 1">
                        <xsl:copy-of select="$currentPage" />
                    </xsl:when>
                    <!-- check if the current page has any children nodes - so if, use it -->
                    <xsl:when test="count($currentPage/node) &gt; 0">
                        <xsl:copy-of select="$currentPage" />
                    </xsl:when>
                    <!-- else move up a little (to the parent node), as we know it has children -->
                    <xsl:otherwise>
                        <xsl:copy-of select="$currentPage/parent::node" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
    
            <!-- loop through the nodes -->
            <xsl:for-each select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']">
                <a href="{umbraco.library:NiceUrl(@id)}">
                    <xsl:if test="$currentPage/ancestor-or-self::node/@id = current()/@id">
                        <!-- we're under the item - you can do your own styling here -->
                        <xsl:attribute name="style">
                            background: #990000;
                            border: 1px solid #fff;
                        </xsl:attribute>
                    </xsl:if>
                    <xsl:value-of select="@nodeName" />
                </a>
            </xsl:for-each>
    
        </xsl:template>
    
    </xsl:stylesheet>

    I've added a few comments, so that you can understand what is going on.

    The idea here is that once you drill down to the deepest node, there are no child nodes, so you need to move back up one (except if you are already at the top!).

    Good luck, Lee.

  • Mike 62 posts 274 karma points
    Jan 15, 2010 @ 21:00
    Mike
    0

    Hi Lee,

    This is really great and the commented code is helping me to understand too - which is of great benefit so I do appreciate that.

    The one issue I am now finding with the new code you kindly provided is that the sub-menu is currently just repeating the parent menu. So for example: I have a top level menu called News & Events and when I click this the sub-menu also just says News & Events rather than its child nodes.

    Any ideas?

    Thanks again for your assistance.

    Best wishes,
    Mike

  • Donald St. Martin 83 posts 128 karma points
    Jan 15, 2010 @ 21:48
    Donald St. Martin
    1

    Mike,

    I was looking for the exact same thing so I copied the code Lee provided to see if it would work and I got the same results you did.  What I did was combine Lee's code with some code that came with the Creative Website Starter for the sub-navigation and came up with this:

    <?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"
    exclude-result-prefixes="msxml umbraco.library">


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

    <xsl:param name="currentPage"/>

    <xsl:template match="/">

    <xsl:variable name="menuSource">
    <xsl:choose>

    <!-- if the current page is the root node (as in homepage) - use the current node -->
    <xsl:when test="$currentPage/@level = 1">
    <xsl:copy-of select="$currentPage" />
    </xsl:when>

    <!-- check if the current page has any children nodes - so if, use it -->
    <xsl:when test="count($currentPage/node) &gt; 0">
    <xsl:copy-of select="$currentPage" />
    </xsl:when>

    <!-- else move up a little (to the parent node), as we know it has children -->
    <xsl:otherwise>
    <xsl:copy-of select="$currentPage/parent::node" />
    </xsl:otherwise>

    </xsl:choose>
    </xsl:variable>

    <h2>
    <xsl:value-of select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']/@nodeName"/>
    </h2>

    <!-- loop through the nodes -->
    <div class="secondaryNav">
    <ul>

    <xsl:for-each select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']/node">
    <li>
    <xsl:if test="$currentPage/ancestor-or-self::node/@id = current()/@id">
    <!-- we're under the item - you can do your own styling here -->
    <xsl:attribute name="class">
    <xsl:text>selected</xsl:text>
    </xsl:attribute>
    </xsl:if>

    <a href="{umbraco.library:NiceUrl(@id)}">
    <span>
    <xsl:value-of select="@nodeName" />
    </span>
    </a>
    </li>
    </xsl:for-each>
    </ul>
    </div>
    </xsl:template>

    </xsl:stylesheet>

    I added /node at the end of the for-each statement and did a little bit of re-arranging and got it to work.  Thanks to Lee's code, I have been able to solve something that has been bugging me for a bit now.

    I hope this helps!

    --
    Donald

  • Mike 62 posts 274 karma points
    Jan 15, 2010 @ 23:00
    Mike
    0

    Hi Donald,

    Thanks very much for your post - this has really helped and does indeed solve my problem - thanks very much...

    However, I've noticed that since updating

    <xsl:for-each select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']">

    to

    <xsl:for-each select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']/node">

    The "umbracoNaviHide" function has stopped working - i.e. pages which were hidden from the nav are now appearing in the node list.

    Have you noticed whether yours still works?

    Here's my full XSLT currently:

    <?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"
     exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib BlogLibrary ">

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

    <xsl:param name="currentPage"/>

    <xsl:template match="/">

    <xsl:variable name="menuSource">
     <xsl:choose>
      <!-- if the current page is the root node (as in homepage) - use the current node -->
      <xsl:when test="$currentPage/@level = 1">
       <xsl:copy-of select="$currentPage" />
      </xsl:when>

      <!-- check if the current page has any children nodes - so if, use it -->
      <xsl:when test="count($currentPage/node) &gt; 0">
       <xsl:copy-of select="$currentPage" />
      </xsl:when>

      <!-- else move up a little (to the parent node), as we know it has children -->
      <xsl:otherwise>
       <xsl:copy-of select="$currentPage/parent::node" />
      </xsl:otherwise>  
     </xsl:choose>
    </xsl:variable>

    <!-- loop through the nodes -->
    <xsl:for-each select="msxml:node-set($menuSource)/node[string(data[@alias='umbracoNaviHide']) != '1']/node">
     <a href="{umbraco.library:NiceUrl(@id)}">
      <xsl:if test="$currentPage/ancestor-or-self::node/@id = current()/@id">
       <!-- we're under the item - you can do your own styling here -->
       <xsl:attribute name="style">
        background: #990000;
        border: 1px solid #fff;
       </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="@nodeName" />
     </a>
    </xsl:for-each>

    </xsl:template>

    </xsl:stylesheet>

  • Mike 62 posts 274 karma points
    Jan 16, 2010 @ 01:48
    Mike
    1

    I've resolved the 'umbracoNaviHide' issue by changing

    <xsl:for-each select="msxml:node-set($menuSource)/node/node[string(data[@alias='umbracoNaviHide']) != '1']/node">
    

     

     

    to

    <xsl:for-each select="msxml:node-set($menuSource)/node/node[string(data[@alias='umbracoNaviHide']) != '1']">
    

     

     

    Thanks Donald, Lee and Petr for your assistance in helping me resolve this issue.

Please Sign in or register to post replies

Write your reply to:

Draft