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.
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:
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.
Following on from Petr's suggestion, the following XSLT should work:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<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) > 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!).
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.
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:
<!-- 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) > 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>
<!-- 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>
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.
<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) > 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>
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:
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
Create variable menu_source and use it instead of currentpage in menu xslt foreach block.
Sample (typed from head):
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
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:
Thank you in advance,
Mike
Is anyone able to help me solve this issue?
Hi Mike,
Would you be able to post your XSLT? We should be able to help by example.
Thanks, Lee.
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.
Any guidance would be hugely appreciated.
Best wishes,
Mike
Hi Mike,
Following on from Petr's suggestion, the following XSLT should work:
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.
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
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:
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
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
to
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:
I've resolved the 'umbracoNaviHide' issue by changing
to
Thanks Donald, Lee and Petr for your assistance in helping me resolve this issue.
is working on a reply...