I am new to Umbraco and have templates with navigation that is a set of top level tabs with sub nav dropdown items under each tab. The problem is I need the ability to chose wheather or not the top level tab navigation links to a page or not. All tabs with drop down sub navs don't need to link to anything. I don't know where I would address this? Template, Macro, Doctype? Help please.
You would address this in your macro. It depends on whether you're using XSLT or razor as to exactly how, but the logic would be: iterate through top level nodes; if there are child pages don't add a link element to the current node in the loop; if there aren't child nodes then do add a link element to the current node in the loop. I tend to prefer XSLT but the code should be fairly simple in either XSLT or razor.
If you're struggling with the macro syntax post here what you have so far and someone will point you in the right direction.
I'm not sure what your 'node-link-with-span' template is doing, but you could rearrange the middle bit of the code to declare your 'subnodes' variable then set an href property on the link if there are subnodes like this (I've removed your call to the template to render the link and replaced it with an anchor tag, just to demonstrate):
Here are the templates that are called in the tab navigation. I believe I would have to change the template "node-link-with-span" to achieve the correct effect, but I am having some difficulty with the xsl:when and xsl:otherwise logic. If there are child nodes then I don't want a href applied to the parent node.
<xsl:template name="node-link-with-span"> <xsl:param name="node" /> <xsl:if test="string($node) != ''"> <a> <xsl:attribute name="href"> <xsl:choose> <xsl:when test="$node[name() = 'ExternalLink']"> <xsl:value-of select="$node/url" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="umbraco.library:NiceUrl($node/@id)" /> </xsl:otherwise> </xsl:choose> </xsl:attribute> <span> <xsl:call-template name="node-name"> <xsl:with-param name="node" select="$node" /> </xsl:call-template> </span> </a> </xsl:if> </xsl:template> <!-- A template to output the correct name for a given node. Better than copy/pasting this code all over the place --> <xsl:template name="node-name"> <xsl:param name="node" /> <xsl:if test="string($node) != ''"> <xsl:choose> <xsl:when test="$node/pageTitle != ''"> <xsl:value-of select="$node/pageTitle"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$node/@nodeName"/> </xsl:otherwise> </xsl:choose> </xsl:if> </xsl:template>
Thanks for your suggestions. The first one, I believe would be the correct approch, but as it is only removes the href on the parent for the first page. After any other clicks to child node pages the parent href for the navs with children has an active href when it shouldn't. Any suggestions ?
The first example doesn't remove the href, it populates it with href="javascript://" which essentially does nothing but preserve any styling you may have that follows a markup pattern. You are right, it may inherit active styling because it's not associated with a page or anchor.
I typically set a blanket styling for nav links and set a class name for the branch I'm on so I have control over the appearance. Here's an example of XSLT I use:
How could I alter your xslt to allow for child nodes to have links if they had granchildren? As it is now adding grandchildren makes the parent node receive the "javascript://" link.
Thanks John. I'ts been so long since I has asked this question I don't know wheather or not I had figured this out or not. I might have even just re-wrote it as a Razor script. From what I understand about xslt now, it appears that your idea is the answer to my last question though. ;)
Template links
I am new to Umbraco and have templates with navigation that is a set of top level tabs with sub nav dropdown items under each tab. The problem is I need the ability to chose wheather or not the top level tab navigation links to a page or not. All tabs with drop down sub navs don't need to link to anything. I don't know where I would address this? Template, Macro, Doctype? Help please.
Hi Steve,
You would address this in your macro. It depends on whether you're using XSLT or razor as to exactly how, but the logic would be: iterate through top level nodes; if there are child pages don't add a link element to the current node in the loop; if there aren't child nodes then do add a link element to the current node in the loop. I tend to prefer XSLT but the code should be fairly simple in either XSLT or razor.
If you're struggling with the macro syntax post here what you have so far and someone will point you in the right direction.
Thanks Dan,
Here is the code I am using for my tabed navigation. Would my solution be as simple a changing the axes wherever it refrences this:
<xsl:variable name="home" select="$currentPage/ancestor-or-self::Category2HomePage" />
To:
<xsl:variable name="home" select="$currentPage/ancestor::Category2HomePage" />
? Let me know if I am missing somthing else. Thanks again!
MY XSLT NAVIGATION:
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:param name="currentPage"/>
<xsl:template match="/">
<xsl:variable name="home" select="$currentPage/ancestor-or-self::Category2HomePage" />
<xsl:variable name="nav" select="$home/*[@isDoc and string(umbracoNaviHide)!='1']" />
<ul>
<xsl:if test="string($home/useAlternateNavigation) = '1'">
<xsl:attribute name="class">alt-nav</xsl:attribute>
</xsl:if>
<xsl:for-each select="$nav">
<li>
<!-- this craziness allows IE to lay subnavs on top of top nav elements if they break onto two lines -->
<xsl:attribute name="style">z-index:<xsl:value-of select="count($nav)-position()+1" />;</xsl:attribute>
<xsl:attribute name="class">
<xsl:if test="$currentPage/ancestor-or-self::*[@isDoc and name()!='Category2HomePage' and @id=current()/@id]">
<xsl:text>active</xsl:text>
</xsl:if>
<xsl:text> </xsl:text>
<xsl:if test="count($nav)=position()">
<xsl:text>last</xsl:text>
</xsl:if>
</xsl:attribute>
<xsl:call-template name="node-link-with-span">
<xsl:with-param name="node" select="current()" />
</xsl:call-template>
<xsl:variable name="subnodes" select="* [@isDoc and string(umbracoNaviHide)!='1']" />
<xsl:if test="$subnodes">
<ul>
<xsl:for-each select="$subnodes">
<li>
<xsl:if test="position()=1">
<xsl:attribute name="class">first</xsl:attribute>
</xsl:if>
<xsl:call-template name="node-link-with-span">
<xsl:with-param name="node" select="current()" />
</xsl:call-template>
</li>
</xsl:for-each>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</ul>
Hi,
I'm not sure what your 'node-link-with-span' template is doing, but you could rearrange the middle bit of the code to declare your 'subnodes' variable then set an href property on the link if there are subnodes like this (I've removed your call to the template to render the link and replaced it with an anchor tag, just to demonstrate):
You can obviously do that logic within your template, passing $subnodes to it (or even a 'count($subnodes)') but hopefully you get the idea...
Dan,
Here are the templates that are called in the tab navigation. I believe I would have to change the template "node-link-with-span" to achieve the correct effect, but I am having some difficulty with the xsl:when and xsl:otherwise logic. If there are child nodes then I don't want a href applied to the parent node.
<xsl:template name="node-link-with-span">
<xsl:param name="node" />
<xsl:if test="string($node) != ''">
<a>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="$node[name() = 'ExternalLink']">
<xsl:value-of select="$node/url" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="umbraco.library:NiceUrl($node/@id)" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<span>
<xsl:call-template name="node-name">
<xsl:with-param name="node" select="$node" />
</xsl:call-template>
</span>
</a>
</xsl:if>
</xsl:template>
<!-- A template to output the correct name for a given node. Better than copy/pasting this code all over the place -->
<xsl:template name="node-name">
<xsl:param name="node" />
<xsl:if test="string($node) != ''">
<xsl:choose>
<xsl:when test="$node/pageTitle != ''">
<xsl:value-of select="$node/pageTitle"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$node/@nodeName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
At first I was thinking you could just add another case to your choose statement:
<a>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="count($node/* [@isDoc and string(umbracoNaviHide) != '1'])">
<![CDATA[javascript://]]>
</xsl:when>
<xsl:when test="$node[name() = 'ExternalLink']">
<xsl:value-of select="$node/url" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="umbraco.library:NiceUrl($node/@id)" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<span>
<xsl:call-template name="node-name">
<xsl:with-param name="node" select="$node" />
</xsl:call-template>
</span>
</a>
But if you don't want the anchor altogether I think you could do the following:
<xsl:template name="node-link-with-span">
<xsl:param name="node" />
<xsl:choose>
<xsl:when test="string($node) = ''"><!-- skip --></xsl:when>
<xsl:when test="count($node/* [@isDoc and string(umbracoNaviHide) != '1'])">
<span>
<xsl:call-template name="node-name">
<xsl:with-param name="node" select="$node" />
</xsl:call-template>
</span>
</xsl:when>
<xsl:when test="$node[name() = 'ExternalLink']">
<a>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="$node[name() = 'ExternalLink']">
<xsl:value-of select="$node/url" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="umbraco.library:NiceUrl($node/@id)" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<span>
<xsl:call-template name="node-name">
<xsl:with-param name="node" select="$node" />
</xsl:call-template>
</span>
</a>
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:template>
Jon,
Thanks for your suggestions. The first one, I believe would be the correct approch, but as it is only removes the href on the parent for the first page. After any other clicks to child node pages the parent href for the navs with children has an active href when it shouldn't. Any suggestions ?
The first example doesn't remove the href, it populates it with href="javascript://" which essentially does nothing but preserve any styling you may have that follows a markup pattern. You are right, it may inherit active styling because it's not associated with a page or anchor.
I typically set a blanket styling for nav links and set a class name for the branch I'm on so I have control over the appearance. Here's an example of XSLT I use:
<?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" 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"
exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets ">
<xsl:output method="html" omit-xml-declaration="yes" />
<xsl:param name="currentPage"/>
<xsl:variable name="maxLevel"><xsl:choose>
<xsl:when test="macro/maxLevel != ''"><xsl:value-of select="macro/maxLevel" /></xsl:when>
<xsl:otherwise>2</xsl:otherwise></xsl:choose></xsl:variable>
<xsl:template match="/">
<ul class="nav">
<xsl:call-template name="drawNodes">
<xsl:with-param name="parent" select="$currentPage/ancestor-or-self::* [@isDoc and @level=1]"/>
</xsl:call-template>
</ul>
</xsl:template>
<xsl:template name="drawNodes">
<xsl:param name="parent"/>
<xsl:for-each select="$parent/* [@isDoc and string(umbracoNaviHide) != '1' and @level <= $maxLevel]">
<li>
<xsl:attribute name="class">nav-item nav-item-<xsl:value-of select="position()" /></xsl:attribute>
<a>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="./externalRedirectURL != ''">
<xsl:value-of select="./externalRedirectURL" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="umbraco.library:NiceUrl(@id)" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="string(./topNavNewWindow) = '1'">
<xsl:attribute name="target">_blank</xsl:attribute>
</xsl:if>
<xsl:if test="$currentPage/ancestor-or-self::* [@isDoc and @id = current()/@id]">
<xsl:attribute name="class">on</xsl:attribute>
<xsl:attribute name="rel">nofollow</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="./topNavText != ''">
<xsl:value-of select="./topNavText" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@nodeName"/>
</xsl:otherwise>
</xsl:choose>
</a>
<xsl:if test="count(./* [@isDoc and string(umbracoNaviHide) != '1' and @level <= $maxLevel])">
<ul>
<xsl:call-template name="drawNodes">
<xsl:with-param name="parent" select="."/>
</xsl:call-template>
</ul>
</xsl:if>
</li>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
And a snippet of styling I may have:
ul.nav { margin:0; padding: 0; text-align:center; }
ul.nav li {
display:inline-block;
position:relative;
padding-top:1px;
margin:0;
}
.lt-ie9 ul.nav li { display:inline; }
ul.nav li a {
display:block;
color:#fff;
text-decoration:none;
text-transform:uppercase;
padding:0 15px;
}
.lt-ie9 ul.nav li a { display:inline; }
ul.nav li a.on { text-decoration:underline; }
ul.nav li:hover { background: #ccc; }
ul.nav li:hover ul { display:block; }
ul.nav ul {
display:none;
position:absolute;
z-index:99999;
top:23px;
left:-3px;
width:165px;
}
ul.nav ul li {
clear:left;
float:none;
background: #fff;
width:165px;
padding:0;
margin:0;
}
ul.nav ul li a {
color:#000;
text-align:center;
text-decoration:none;
text-transform:none;
display:block;
width:165px;
height: auto;
background:#fff;
border-top: none;
border-right: none;
border-bottom: 1px solid #ccc;
clear: left;
padding: 4px 4px;
margin:0;
}
ul.nav ul li a:hover {
background: #ccc;
color: #000;
text-decoration: none;
}
Thanks for your help works great!! I appreciate your time!
One more question :)
How could I alter your xslt to allow for child nodes to have links if they had granchildren? As it is now adding grandchildren makes the parent node receive the "javascript://" link.
You may need to get the crayons out and sketch it out for me.
This what you are desiring? (non-linked represent anchors with href="javascript://")
However, the tidbit of XSLT you are using is doing this?
So, if I'm following correctly, you may just need to update your case with a level expression, so something like this:
<a>
<xsl:attribute name="href">
<xsl:choose>
<xsl:when test="count($node/* [@isDoc and string(umbracoNaviHide) != '1']) and $node/@level <= 2">
<![CDATA[javascript://]]>
</xsl:when>
<xsl:when test="$node[name() = 'ExternalLink']">
<xsl:value-of select="$node/url" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="umbraco.library:NiceUrl($node/@id)" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<span>
<xsl:call-template name="node-name">
<xsl:with-param name="node" select="$node" />
</xsl:call-template>
</span>
</a>
Thanks John. I'ts been so long since I has asked this question I don't know wheather or not I had figured this out or not. I might have even just re-wrote it as a Razor script. From what I understand about xslt now, it appears that your idea is the answer to my last question though. ;)
is working on a reply...