Hi! I'm new to Umbraco and Razor engine. I'm just experimenting around and I'm positively impressed by what can be achieved using Razor scripts and macros.
However, I'm having some difficulties. For example:
When I create a new Razor Script directly from the Umbraco admin interface with the Select Children by Document Type - Dynamic Node template, the script doesn't work.
But I have to change @Model.ChildItem.Where... to @Model.Children.Where...
Anyway, this is not a great problem.
Now, I'm searching for a way to get the root element of my content because I want to create a dynamic menu for my web pages.
With the previous script I can get all the children of a node. But I want to create a classic menu starting from "node 0", in order to get a classic Home, About, Products, Contacts menu.
I hope I've been straightforward in my request. Thanks!
@{ var startLevel = 1; var finishLevel = 2; var parent = @Model.AncestorOrSelf(startLevel); if (parent != null) { @ulMenu(parent, startLevel, finishLevel) ; } }
@helper ulMenu(dynamic parent, int startLevel, int finishLevel) { var count = 0; <ul> @foreach (var node in parent.Children.Where("Visible")) { if (node.template > 0 && node.HasAccess) { <li> <a href="@node.Url">@node.Name</a> @if (@node.Level <= finishLevel) { @ulMenu(node, startLevel, finishLevel); } </li> count++; } } </ul> }
This will create a 2-level dropdown menu from your root node. The key is the AncestorOrSelf method - this can be used to tell Umbraco when to stop climbing the tree or can be used without a parameter to go from the root node: AncestorOrSelf()
If you do not want a nested dropdown but just a menu bar, remove the nested call to @ulMenu in between the <li>..</li>
Try to restructure you site and have a root node "Website" then put home, about us, and any other pages you want at the level. Use the umbracoInternalRedirectId document type property on the website node to redirect into home.
Or, perhaps easier - put all your top level pages within homepage and hard code a homepage link in the scriptas follows
(just inside the <ul> tag before the for each loop)
<li><a href=/">Home</a></li>
if you are creating a dropdown menu you will need to ensure this only runs when the (@parent.Level == startLevel)
e.g.
if ((@parent.Level == startLevel)) {<li><a href=/">Home</a></li>}
The thing is this. You are looking to get a reference to the root node of your site (which in your case is Homepage') - and then your script terates over the children of that node. So, in your structure, 'About Us' will never appear as it is not a child of your root node.
Model.AncestorOrSelf();
THe above code definitely will return the value of the Homepage node on your system. But the rest of the code will only return the children of it.
THis is why a lot of people use a "Site Settings" document type as their root node, then you can have Home and About Us etc at the same level. If you create the document type with no template, the actual homepage of you site will be move to the next node down anyway so you dont have to worry about the umbracoInternalRedirectIdproperty.
For your reference though, you create this property yourself (content picker datatype) and then Umbraco automatically routes through to the chosen page internally
Root and menus
Hi! I'm new to Umbraco and Razor engine. I'm just experimenting around and I'm positively impressed by what can be achieved using Razor scripts and macros.
However, I'm having some difficulties. For example:
When I create a new Razor Script directly from the Umbraco admin interface with the Select Children by Document Type - Dynamic Node template, the script doesn't work.
It generates:
@foreach (var item in @Model.ChildItem.Where("umbracoNaviHide != true"))
{
<li><a href="@item.Url">@item.Name</a></li>
}
But I have to change @Model.ChildItem.Where... to @Model.Children.Where...
Anyway, this is not a great problem.
Now, I'm searching for a way to get the root element of my content because I want to create a dynamic menu for my web pages.
With the previous script I can get all the children of a node. But I want to create a classic menu starting from "node 0", in order to get a classic Home, About, Products, Contacts menu.
I hope I've been straightforward in my request. Thanks!
Hi Daliz, try this:
@{
var startLevel = 1;
var finishLevel = 2;
var parent = @Model.AncestorOrSelf(startLevel);
if (parent != null) { @ulMenu(parent, startLevel, finishLevel) ; }
}
@helper ulMenu(dynamic parent, int startLevel, int finishLevel)
{
var count = 0;
<ul>
@foreach (var node in parent.Children.Where("Visible")) {
if (node.template > 0 && node.HasAccess)
{
<li>
<a href="@node.Url">@node.Name</a>
@if (@node.Level <= finishLevel) { @ulMenu(node, startLevel, finishLevel); }
</li>
count++;
}
}
</ul>
}
This will create a 2-level dropdown menu from your root node. The key is the AncestorOrSelf method - this can be used to tell Umbraco when to stop climbing the tree or can be used without a parameter to go from the root node: AncestorOrSelf()
If you do not want a nested dropdown but just a menu bar, remove the nested call to @ulMenu in between the <li>..</li>
Thank you, Barry (I named the Razor script "RazorBarry" in your honor ;-)).
Anyway, with your script, I'm still getting only the children of the active page.
I'd like to get, wherever I am, a menu with links to: Homepage, About Me.
Instead, if I'm viewing Homepage, I'm getting the subpages of Homepage.
Try to restructure you site and have a root node "Website" then put home, about us, and any other pages you want at the level. Use the umbracoInternalRedirectId document type property on the website node to redirect into home.
Or, perhaps easier - put all your top level pages within homepage and hard code a homepage link in the scriptas follows
(just inside the <ul> tag before the for each loop)
<li><a href=/">Home</a></li>
if you are creating a dropdown menu you will need to ensure this only runs when the (@parent.Level == startLevel)
e.g.
if ((@parent.Level == startLevel)) {<li><a href=/">Home</a></li>}
Ok, that's good.
What do you think of using the hard-coded page id?
@{
var node = @Model.NodeById(1051);
}
@foreach (var item in @node.Children) {
<p><a href="@item.Url">@item.Name</a></p>
}
I was thinking of this because I can't find this umbracoInternalRedirectId property.
The thing is this. You are looking to get a reference to the root node of your site (which in your case is Homepage') - and then your script terates over the children of that node. So, in your structure, 'About Us' will never appear as it is not a child of your root node.
THe above code definitely will return the value of the Homepage node on your system. But the rest of the code will only return the children of it.
THis is why a lot of people use a "Site Settings" document type as their root node, then you can have Home and About Us etc at the same level. If you create the document type with no template, the actual homepage of you site will be move to the next node down anyway so you dont have to worry about the umbracoInternalRedirectIdproperty.
For your reference though, you create this property yourself (content picker datatype) and then Umbraco automatically routes through to the chosen page internally
As Barry advises, I would restructure your content tree like this:
Content
----------- Homepage
--------------- About Us
--------------- Contact Us
--------------- etc.
Rich
Ok. Thank you.
Hi Daliz, dont forget to mark an answer as the solution! (that way the solution providers get karma points)
is working on a reply...