I would like my dropdown submenu to dropdown from the same place no matter what menu is hovered.
This is my menu right now
This is how I want the dropdown submenu to look like
As you can see, the second image dropdown is displayed under the whole menu and thats what I want.
Is there any way to achieve this?
This is my code right now:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{ var home = CurrentPage.Site(); }
@if (home.Children.Any())
{
@* Get the first page in the children *@
var naviLevel = home.Children.First().Level;
@* Add in level for a CSS hook *@
<div class="linje"></div>
<ul class="meny level-@naviLevel">
@* For each child page under the home node *@
@foreach (var childPage in home.Children)
{
if (childPage.Children.Any())
{
<li class="dropdown has-child @(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
@if (childPage.DocumentTypeAlias == "Huvudmeny")
{
<span>@childPage.Name</span>
@childPages(childPage.Children)
}
else
{
<a href="@childPage.Url" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">@childPage.Name</a>
}
@helper childPages(dynamic pages)
{
@* Ensure that we have a collection of pages *@
if (pages.Any())
{
@* Get the first page in pages and get the level *@
var naviLevel = pages.First().Level;
@* Add in level for a CSS hook *@
<ul class="meny dropdown-menu sublevel level-@(naviLevel)">
@foreach (var page in pages)
{
<li>
<a href="@page.Url">@page.Name</a>
@* if the current page has any children *@
@if (page.Children.Any())
{
@* Call our helper to display the children *@
@childPages(page.Children)
}
</li>
}
</ul>
}
}
</li>
}
else
{
<li class="@(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
<a href="@childPage.Url">@childPage.Name</a>
</li>
}
}
</ul>
<div class="linje col-md-12" ></div>
}
A lot like the sample you've posted. Just look for the html inside and amend to match the output. If you get specific errors or problems I'm sure someone here will help.
I can't use the same css on Razor because I can't target specific menus and sub menus..
Is it even possible having a full width CSS meganav using Razor..?
You sound a little lost. Razor is just code that is used to generate HTML from nodes / content data (and if you're crazy I suppose you could do CSS / JS).
The best, cleanest (IMHO) thing to do is to put your static HTML, CSS and JS in the page template (CSS and JS ideally as referenced, minimised files rather than "inline") and only generate the HTML in razor that you need.
If none of that makes sense I suggest you work through this tutorial with a clean copy of Umbraco... then mists should then clear!
The problem I have is that with Umbraco, everything is dynamic. The user is supposed to create the menu and sub menus themselves.
That mean I can't target specific menu or sub menus. I'll give you an example.
If static the code would look like something like this:
<ul id="menu">
<li>
<a href="#" class="drop">Home</a><!-- Begin Home Item -->
<div class="dropdown_2columns">
<!-- Begin 2 columns container -->
<div class="col_2">
<h2>Welcome !</h2>
</div>
</div><!-- End 2 columns container -->
</li><!-- End Home Item -->
<li>
<a href="#" class="drop">5 Columns</a><!-- Begin 5 columns Item -->
<div class="dropdown_5columns">
<!-- Begin 5 columns container -->
</div><!-- End 5 columns container -->
</li><!-- End 5 columns Item -->
<li>
<a href="#" class="drop">4 Columns</a><!-- Begin 4 columns Item -->
<div class="dropdown_4columns">
<!-- Begin 4 columns container -->
<div class="col_4">
<h2>This is a heading title</h2>
</div>
</div><!-- End 4 columns container -->
</li><!-- End 4 columns Item -->
</ul>
Here we can target specific menus, sub menus , columns etc..
But in Umbraco where everything is dynamic, the code would look something like this:
@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{ var home = CurrentPage.Site(); }
@if (home.Children.Any())
{
@* Get the first page in the children *@
var naviLevel = home.Children.First().Level;
@* Add in level for a CSS hook *@
<div class="linje"></div>
<ul class="meny level-@naviLevel">
@* For each child page under the home node *@
@foreach (var childPage in home.Children)
{
if (childPage.Children.Any())
{
<li class="dropdown has-child @(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
@if (childPage.DocumentTypeAlias == "Huvudmeny")
{
<span>@childPage.Name</span>
@childPages(childPage.Children)
}
else
{
<a href="@childPage.Url" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">@childPage.Name</a>
}
@helper childPages(dynamic pages)
{
@* Ensure that we have a collection of pages *@
if (pages.Any())
{
@* Get the first page in pages and get the level *@
var naviLevel = pages.First().Level;
@* Add in level for a CSS hook *@
<ul class="meny dropdown-menu sublevel level-@(naviLevel)">
@foreach (var page in pages)
{
<li>
<a href="@page.Url">@page.Name</a>
@* if the current page has any children *@
@if (page.Children.Any())
{
@* Call our helper to display the children *@
@childPages(page.Children)
}
</li>
}
</ul>
}
}
</li>
}
else
{
<li class="@(childPage.IsAncestorOrSelf(CurrentPage) ? "selected" : null)">
<a href="@childPage.Url">@childPage.Name</a>
</li>
}
}
</ul>
<div class="linje col-md-12" ></div>
}
As you can see, I can't target specific menus, sub menus, columns because we don't know what the user created yet..
So how can I target specific menus, sub menus and columns in Umbraco?
For creating navs there are two main options I use (please note I tend to use the words Nav and Menu interchangeably... ):
1) A simple looping through content nodes. In Razor you usually get to the homepage node and then loop down outputting content nodes as per the structure of the site to a set number of levels. In razor, it's easy to do counts of nodes etc to add special classes or even if you need special classes for the first, second, third etc.
2) You use a content picker (either in a special SiteSettings node or store it on the homepage) and use a number of content node pickers to allow the user to select the nodes they want to include in the nav. This has the added benefit that not all pages need to be in the nav and the user has full control of ordering of the nav.
There are various methods for dealing with the fact that you'll have a number of root menu items with a number of children underneath. You can either use some kind of special content picker built for the task, build your own or (more limiting) just create a series of pickers. E.g. Menu1, Menu1Children, Menu2. Menu2Children, Menu3... then you can output these as you like checking if values are set and adding special classes to each section.
To do this - go to Developer > Data Types and create two new types called Menu Picker *& Menu Children Picker (*selecting the property editor "Multinode Treepicker", set the max of the Menu Picker to 1).
Now go to your Homepage / Sitesettings Document type (in Settings), add a tab called Nav and add the following:
MenuItem1 - Type MenuPicker
MentItem1Children - Type MenuChildrenPicker
MenuItem2 - Type MenuPicker
MentItem2Children - Type MenuChildrenPicker
... for as many "root" parent menu items as you want the user to be able to set (page design usually means there is a limit).
If you call your node and then add .SortOrder() to the end of the call it will give you its position in the content tree.
So if you loop on them and ask for .Name and .SortOrder() you will see exactly what it is. Then use the value in the div class to give unique div class.
I'm very new to this..
Can you look at my code that I included at the top and give a sample on how it would look like together with my code? I would really appreciate that.
When you say the user should be able to "create the menu and sub menus themselves" do you mean when they create any content in the content tree it should appear or they should have full control and the nav / menu should be configurable separately from the content tree?
Answering your last question though..
From what you had originally it would be simple to do count the children under each child.
int numChildNodes = childPage.Children.Count()
Then put a switch / if-else bit of logic on the value you get there to decide how many columns to oputput - e.g. set a variable "numCols" based on this count. You can then use this variable to output the relevant class names / IDs. Is that what you mean?
<div class="dropdown_@(numCols)columns">
<!-- Begin dynamic number of columns container -->
<div class="col_@(numCols)">
<h2>Welcome !</h2>
</div>
</div><!-- End dynamic number of columns container -->
Thank you, but where in my code can I place that code you just showed me?
And to answer your question, I meant that the user create any content in the content tree it should appear on the nav menu.
Try this - loops through each three child nodes of each main main nodes - hopefully you can tailor this to exactly what you want. If there are nodes lower than two levels look at the note to change .Children to .Descendants.
@{
var rootNode = Model.Content.AncestorOrSelf(1);
// home node is hardcoded - this might not be right?
<ul id="menu">
<li>
<a href="/" class="drop">Home</a>
<div class="dropdown_2columns">
<!-- Begin 2 columns container -->
<div class="col_2">
<h2>Welcome !</h2>
</div>
</div><!-- End 2 columns container -->
</li><!-- End Home Item -->
@foreach (var mainNode in rootNode.Children())
{
int childCount = 1;
int numChildren = mainNode.Children().Count();
<li>
<a href="@mainNode.Url" class="drop">@mainNode.Name</a>
<div class="dropdown_5columns">
<!-- Begin 2 columns container -->
<div class="col_5">
<h2>@mainNode.Name</h2>
</div>
@* note if you want ALL descendants change .Children to .Descendats*@
@foreach (var childNode in mainNode.Children())
{
// if first node or new set of three open the div and ul @: is used to stop razor trying to
// "balance" the tags
if(childCount == 1 || (double)childCount % 3 == 1)
{
@:<div class="col_1">
@:<ul>
}
<a href="@childNode.Url">@childNode.Name</a>
// close the div and list if this is either a multiple of 3 or the last one
if ((double)childCount % 3 == 0 || numChildren == childCount)
{
@:</ul>
@:</div>
}
childCount++;
}
</div>
</li>
}
</ul>
}
// some dummy content to make the code thing work on the forum
Hi Steve,
Thank you, but the code is not working.
I get this error:
Encountered end tag "div" with no matching start tag. Are your
start/end tags properly balanced?
and
'Umbraco.Core.Models.IPublishedContent' does not contain a definition
for 'AncestorOrSelf' and no extension method 'AncestorOrSelf'
accepting a first argument of type
'Umbraco.Core.Models.IPublishedContent' could be found (are you
missing a using directive or an assembly reference?)
@inherits Umbraco.Web.Macros.PartialViewMacroPage
@{
var rootNode = Model.Content.AncestorOrSelf(1);
// home node is hardcoded - this might not be right?
<ul id="menu">
<li>
<a href="/" class="drop">Home</a>
<div class="dropdown_2columns">
<!-- Begin 2 columns container -->
<div class="col_2">
<h2>Welcome !</h2>
</div>
</div><!-- End 2 columns container -->
</li><!-- End Home Item -->
@foreach (var mainNode in rootNode.Children())
{
int childCount = 1;
int numChildren = mainNode.Children().Count();
<li>
<a href="@mainNode.Url" class="drop">@mainNode.Name</a>
<div class="dropdown_5columns">
<!-- Begin 2 columns container -->
<div class="col_5">
<h2>@mainNode.Name</h2>
</div>
@* note if you want ALL descendants change .Children to .Descendats*@
@foreach (var childNode in mainNode.Children())
{
// if first node or new set of three open the div and ul @: is used to stop razor trying to
// "balance" the tags
if (childCount == 1 || (double)childCount % 3 == 1)
{
@:<div class="col_1">
@:<ul>
}
<a href="@childNode.Url">@childNode.Name</a>
// close the div and list if this is either a multiple of 3 or the last one
if ((double)childCount % 3 == 0 || numChildren == childCount)
{
@:</ul>
@:</div>
}
childCount++;
}
</div>
</li>
}
</ul>
}
When you paste it in ensure that lines 35, 36, 43 and 44 are not reformatted if you use Visual Studio. It loves to autoformat and change @:</ul> to something on two lines which then breaks the macro with the error you're seeing.
Sub menu drop-down under entire menu
I would like my dropdown submenu to dropdown from the same place no matter what menu is hovered.
This is my menu right now
This is how I want the dropdown submenu to look like
As you can see, the second image dropdown is displayed under the whole menu and thats what I want. Is there any way to achieve this?
This is my code right now:
Css:
Hi,
This is more of a CSS job. I'd recommend you get this working on a flat HTML version first before complicating matters with Razor.
Take a look at this for inspiration! http://jsfiddle.net/Pnn6V/9/
There are lots of examples of these kinds of meganav out there - just google "Full width CSS meganav" or similar.
Good luck! Steve
Hi Steve, Lets say I want this: http://jsfiddle.net/Pnn6V/377/
How would that look in Razor?
A lot like the sample you've posted. Just look for the html inside and amend to match the output. If you get specific errors or problems I'm sure someone here will help.
I can't use the same css on Razor because I can't target specific menus and sub menus.. Is it even possible having a full width CSS meganav using Razor..?
Hi,
You sound a little lost. Razor is just code that is used to generate HTML from nodes / content data (and if you're crazy I suppose you could do CSS / JS).
The best, cleanest (IMHO) thing to do is to put your static HTML, CSS and JS in the page template (CSS and JS ideally as referenced, minimised files rather than "inline") and only generate the HTML in razor that you need.
If none of that makes sense I suggest you work through this tutorial with a clean copy of Umbraco... then mists should then clear!
https://our.umbraco.org/documentation/tutorials/creating-basic-site/
HTH
Steve
This is what I want: http://jsfiddle.net/Pnn6V/378/
The problem I have is that with Umbraco, everything is dynamic. The user is supposed to create the menu and sub menus themselves.
That mean I can't target specific menu or sub menus. I'll give you an example.
If static the code would look like something like this:
Here we can target specific menus, sub menus , columns etc..
But in Umbraco where everything is dynamic, the code would look something like this:
As you can see, I can't target specific menus, sub menus, columns because we don't know what the user created yet..
So how can I target specific menus, sub menus and columns in Umbraco?
Hi,
For creating navs there are two main options I use (please note I tend to use the words Nav and Menu interchangeably... ):
1) A simple looping through content nodes. In Razor you usually get to the homepage node and then loop down outputting content nodes as per the structure of the site to a set number of levels. In razor, it's easy to do counts of nodes etc to add special classes or even if you need special classes for the first, second, third etc.
2) You use a content picker (either in a special SiteSettings node or store it on the homepage) and use a number of content node pickers to allow the user to select the nodes they want to include in the nav. This has the added benefit that not all pages need to be in the nav and the user has full control of ordering of the nav.
There are various methods for dealing with the fact that you'll have a number of root menu items with a number of children underneath. You can either use some kind of special content picker built for the task, build your own or (more limiting) just create a series of pickers. E.g. Menu1, Menu1Children, Menu2. Menu2Children, Menu3... then you can output these as you like checking if values are set and adding special classes to each section.
To do this - go to Developer > Data Types and create two new types called Menu Picker *& Menu Children Picker (*selecting the property editor "Multinode Treepicker", set the max of the Menu Picker to 1).
Now go to your Homepage / Sitesettings Document type (in Settings), add a tab called Nav and add the following:
... for as many "root" parent menu items as you want the user to be able to set (page design usually means there is a limit).
To help you get started outputting the content from the Multinode Treepickers see this: https://our.umbraco.org/documentation/getting-started/backoffice/property-editors/built-in-property-editors/multinode-treepicker
HTH
Steve
Hi
A quick answer.
If you need a unique value for each of your parent nodes in the top row of your navigation, you could use the sort order as a reference.
var columnNumber =home.Children.SortOrder()
Even if you move the nodes around, the css will hold up. It would give you the chance to align left, align right etc.
Use where you have "dropdown_4columns". I think that is what you are looking at.
It may not be exactly right but should give you a direction to go in.
Regards
Gary
Hi,
Can you give me an example on how to count the nodes so that I can add classes for each individual node, for example the first, second and so on.
Hi
It is above.
If you call your node and then add .SortOrder() to the end of the call it will give you its position in the content tree.
So if you loop on them and ask for .Name and .SortOrder() you will see exactly what it is. Then use the value in the div class to give unique div class.
Regards
Gary
I'm very new to this.. Can you look at my code that I included at the top and give a sample on how it would look like together with my code? I would really appreciate that.
HTH
Johan
Hi Johan,
When you say the user should be able to "create the menu and sub menus themselves" do you mean when they create any content in the content tree it should appear or they should have full control and the nav / menu should be configurable separately from the content tree?
Answering your last question though.. From what you had originally it would be simple to do count the children under each child.
int numChildNodes = childPage.Children.Count()
Then put a switch / if-else bit of logic on the value you get there to decide how many columns to oputput - e.g. set a variable "numCols" based on this count. You can then use this variable to output the relevant class names / IDs. Is that what you mean?
Here's a nice starting point of using a content picker to generate your nav.
https://our.umbraco.org/forum/using/ui-questions/58124-Umbraco-7-build-navigation-from-MultiNode-Tree-Picker
Hi Steve,
Thank you, but where in my code can I place that code you just showed me? And to answer your question, I meant that the user create any content in the content tree it should appear on the nav menu.
Hi Johan
I am a bit busy today to write some code and don't have any code I can modify quickly.
If you can wait, I will try to do something later today, but can't say exactly when.
Hope it helps
Gary
Alright, thank you
Try this - loops through each three child nodes of each main main nodes - hopefully you can tailor this to exactly what you want. If there are nodes lower than two levels look at the note to change .Children to .Descendants.
Hope that is of help.
Hi Steve, Thank you, but the code is not working. I get this error:
That was a snippet - did you just copy and paste that over the top of your template?
Actually where are you pasting this into a template or a partial view macro? Also what version of Umbraco are you using?
If it's a template - here is a complete example NOTE - the amount of code / logic really should be moved out of the template and into a PV Macro.
If you don't have child templates (e.g. a base / master) then delete the line @RenderBody()
I was copy and pasting it into a partial view macro. I'm using Umbraco 7.3.1.
I tried the template code in my master template but I'm getting the same error
Hi,
Here's a PV example.
When you paste it in ensure that lines 35, 36, 43 and 44 are not reformatted if you use Visual Studio. It loves to autoformat and change
@:</ul>
to something on two lines which then breaks the macro with the error you're seeing.Steve, thank you!! I love you!!
Steve, the code doesn't make every drop-down column for every drop-down.. How can I fix this?
is working on a reply...