My subnav currently renders only the children of the current node. How do I get this to also render the parent node. Similarly how do I get it to render the child + parent node when on a grandchild node? In other words no matter on what level the displayed page is I’d like the subnav to display all children and grandchildren back up to their respective parent node whilst only displaying the child nodes if on parent (as it does at present).
Here's the approach that makes most sense for building navigation from scratch:
You want to render a list item with a link for every page (Document) included in the nav - so create a template for that.
Document nodes have an "isDoc" attribute so we'll match anything that has one of those:
<!-- Template for a page -->
<xsl:template match="*[@isDoc]">
<li>
<!-- Render the link to this page -->
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName" />
</a>
</li>
</xsl:template>
Then to render the actual nav, you start it off in the root template (match="/") - but instead of using $currentPage/blah-blah, do yourself a favor and create a siteRoot variable right away - it makes it so much easier to understand what's going on:
<!-- Set a variable for the Home node of the website (usually at level 1) -->
<xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
<xsl:template match="/">
<ul>
<!-- Start the navigation by rendering children of $siteRoot -->
<xsl:apply-templates select="$siteRoot/*[@isDoc]" />
</ul>
</xsl:template>
So far so good - now, you want to render childnodes too, so modify the Document template to check for those and start a new <ul> if present and then use the magic of <xsl:apply-templates /> to recurse down the tree, rendering children, grandchildren etc.:
<!-- Template for a page -->
<xsl:template match="*[@isDoc]">
<li>
<!-- Render the link to this page -->
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName" />
</a>
<!-- Render children (if any) -->
<xsl:if test="*[@isDoc]">
<ul>
<xsl:apply-templates select="*[@isDoc]" />
</ul>
</xsl:if>
</li>
</xsl:template>
So the final XSLT looks something like this (not concerned about hidden nodes for now):
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:umbraco.library="urn:umbraco.library"
exclude-result-prefixes="umbraco.library"
>
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:param name="currentPage" />
<!-- Set a variable for the Home node of the website (usually at level 1) -->
<xsl:variable name="siteRoot" select="$currentPage/ancestor-or-self::*[@level = 1]" />
<xsl:template match="/">
<ul>
<!-- Start the navigation by rendering children of $siteRoot -->
<xsl:apply-templates select="$siteRoot/*[@isDoc]" />
</ul>
</xsl:template>
<!-- Template for a page -->
<xsl:template match="*[@isDoc]">
<li>
<!-- Render the link to this page -->
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName" />
</a>
<!-- Render children (if any) -->
<xsl:if test="*[@isDoc]">
<ul>
<xsl:apply-templates select="*[@isDoc]" />
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
Now get that to work and then come back here with the other requirements :-)
I've now got all pages included in the SubNav as per your instructions. As it's a sub nav I don't want all pages and I'm back now for the other requirements.
Great - so 1st up is getting only the "current tree", which you get by adding a criterion to the existing test, to look for currentPage somewhere below (or at) the node being rendered:
<!-- Template for a page -->
<xsl:template match="*[@isDoc]">
<li>
<!-- Render the link to this page -->
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:value-of select="@nodeName" />
</a>
<!-- Render children (if currentPage is in this branch) --><xsl:if test="descendant-or-self::*[@id = $currentPage/@id]">
<ul>
<xsl:apply-templates select="*[@isDoc]" />
</ul>
</xsl:if>
</li>
</xsl:template>
This should make sure that only one branch is expanded - the one containing $currentPage.
This is all "standard" navigation behavior, but then comes your requirement - if you're on on of the "top level" pages ("Parent 1" or "Parent2") you only want the next level displayed, right? But do you want to expand both, or only the one you're on?
Let me know if my assumptions are correct - then we'll continue from there.
What I mean by too many is that your xslt displays all the level 2 nodes even when a level 3 has been selected and I want to display only the level 2 of that particular level 3 (child). I've got all the nodes from level 2 which is good for the main categories. When I select the main category node all the main categories are still there with the addition of the child of the selected node.
What I want to achieve is when on level 3 to also display level 2 and when on level 4 to also display level 3 and 2.
In my original xslt the only way a user has to navigate back to the parent (level 1) is to use the breadcrumb navigation.
Basically what I want is the same as a breadcrumb (a way for the user to navigate back up the tree to its respective parent) without displaying all of the level 2 nodes. Hope this makes sense.
SubNav help needed please
My subnav currently renders only the children of the current node. How do I get this to also render the parent node. Similarly how do I get it to render the child + parent node when on a grandchild node? In other words no matter on what level the displayed page is I’d like the subnav to display all children and grandchildren back up to their respective parent node whilst only displaying the child nodes if on parent (as it does at present).
Home
Parent 1
Child 1
Grandchild 1
Grandchild 2
Child 2
Parent 2
Child 1
Grandchild 1
Grandchild 2
Child 2
My current xslt is:
Hi Bizzie,
Here's the approach that makes most sense for building navigation from scratch:
You want to render a list item with a link for every page (Document) included in the nav - so create a template for that.
Document nodes have an "isDoc" attribute so we'll match anything that has one of those:
Then to render the actual nav, you start it off in the root template (match="/") - but instead of using $currentPage/blah-blah, do yourself a favor and create a siteRoot variable right away - it makes it so much easier to understand what's going on:
So far so good - now, you want to render childnodes too, so modify the Document template to check for those and start a new <ul> if present and then use the magic of <xsl:apply-templates /> to recurse down the tree, rendering children, grandchildren etc.:
Now get that to work and then come back here with the other requirements :-)
/Chriztian
Hi Chriztian
Many thanks for your time and clear explanations.
I've now got all pages included in the SubNav as per your instructions. As it's a sub nav I don't want all pages and I'm back now for the other requirements.
Great - so 1st up is getting only the "current tree", which you get by adding a criterion to the existing test, to look for currentPage somewhere below (or at) the node being rendered:
This should make sure that only one branch is expanded - the one containing $currentPage.
This is all "standard" navigation behavior, but then comes your requirement - if you're on on of the "top level" pages ("Parent 1" or "Parent2") you only want the next level displayed, right? But do you want to expand both, or only the one you're on?
Let me know if my assumptions are correct - then we'll continue from there.
/Chriztian
I've now got too many nav items listed.
As it's a subnav I've changed this
to start at level 2 but I still have too many on all the pages.
My original sub nav did go down the tree correctly but I want it to also display all the lelels up to their respective parents.
Hi Bizzie,
By "too many", which do you mean? - Could you maybe show what you get compared to what you want?
It's just a matter of tweaking the select's to get the correct nodes (as you already did with the $siteRoot).
/Chriztian
<a href="{umbraco.library:NiceUrl(@id)}">
<xsl:if test="$currentPage/ancestor-or-self::*[@level=2]/@id=@id">
<xsl:attribute name="class"> active</xsl:attribute>
</xsl:if>
<xsl:value-of select="@nodeName"/>
</a>
give "a" tag a special class name "active", then use css to specialize it.
I use this way to highlight main menu item which sub menu are active.
Hope this can give you help
Hi Chriztian, I'm so glad you didn't abandon me!
What I mean by too many is that your xslt displays all the level 2 nodes even when a level 3 has been selected and I want to display only the level 2 of that particular level 3 (child). I've got all the nodes from level 2 which is good for the main categories. When I select the main category node all the main categories are still there with the addition of the child of the selected node.
What I want to achieve is when on level 3 to also display level 2 and when on level 4 to also display level 3 and 2.
In my original xslt the only way a user has to navigate back to the parent (level 1) is to use the breadcrumb navigation.
Basically what I want is the same as a breadcrumb (a way for the user to navigate back up the tree to its respective parent) without displaying all of the level 2 nodes. Hope this makes sense.
is working on a reply...