Hi I want to add a class of "active" to my li, if it is active or if I am on a page under that. I have the following code
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = null;
}
<nav class="topNav">
<ul>
#foreach (var item in Model.Content.AncestorOrSelf(1).Children.Where(x => x.IsVisible() && x.IsDocumentType("Subfrontpage") || x.IsDocumentType("Procesguide")))
{
<li>
#item.Name
</li>
}
</ul>
</nav>
I think I can do something with this, but it gives an error
var isSelected = Model.Path.Contains(item.Id.ToString()) ? "active" : "";
<li class="#Html.Raw(isSelected)">
#item.Name
</li>
This is the error I get. Line 10.
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS1061: 'Umbraco.Web.Models.RenderModel' does not contain a definition for 'Path' and no extension method 'Path' accepting a first argument of type 'Umbraco.Web.Models.RenderModel' could be found (are you missing a using directive or an assembly reference?)
Source Error:
Line 8: #foreach (var item in Model.Content.AncestorOrSelf(1).Children.Where(x => x.IsVisible() && x.IsDocumentType("Subfrontpage") || x.IsDocumentType("Procesguide")))
Line 9: {
Line 10: var isSelected = Model.Path.Contains(item.Id.ToString()) ? "active" : "";
Line 11:
Line 12: <li class="#Html.Raw(isSelected)">
I have now tried with this, but no lunk
<ul>
<li>
#home.Name
</li>
#foreach (var item in Model.Content.AncestorOrSelf(1).Children.Where(x => x.IsVisible() && x.IsDocumentType("Subfrontpage") || x.IsDocumentType("Procesguide")))
{
var isSelected = item.IsDescendant(Model,"active", "");
<li class="#Html.Raw(isSelected)">
#item.Name
</li>
}
</ul>
ok here is the solution. This is for typed, not dynamic cshtml.
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = null;
var home = Model.Content.AncestorOrSelf(1);
}
<ul>
#*Render Home item*#
#{ var homeActive = ""; }
#if( home.Id == Model.Content.Id){
homeActive = "active";
}
<li class="#homeActive">
<a href="#home.Url">
#home.Name
</a>
</li>
#*Render Home children*#
#foreach (var item in home.Children.Where(x => x.IsVisible()))
{
var active = "";
if(home.Id != Model.Content.Id){ #* if NOT home *#
if (item.Id == Model.Content.AncestorOrSelf(2).Id){
#* if foreach id and currentpage ancestor id is equal *#
active = "active";
}
}
<li class="#active">
<a href="#item.Url">
#item.Name
</a>
</li>
}
</ul>
You can try something like this:
var isSelected = item.IsDescendant(Model,"active", "");
Here is a list of the functions you can use:
#Model.AncestorOrSelf(string nodeTypeAlias)
#Model.AncestorOrSelf(int level)
#Model.AncestorOrSelf(Func<DynamicNode, bool> func)
and those Helper functions:
#Model.IsDescendant(DynamicNode[,valueIfTrue][,valueIfFalse])
#Model.IsDescendantOrSelf(DynamicNode[,valueIfTrue][,valueIfFalse])
Reference: Is the current page a descendant of a specific node id?
The following is the default script for navigation produced by umbraco:
#inherits umbraco.MacroEngines.DynamicNodeContext
#*
Macro to display child pages below the root page of a standard website.
Also highlights the current active page/section in the navigation with
the css class "current".
*#
#{
#*Get the root of the website *#
var root = Model.AncestorOrSelf(1);
}
<ul>
#foreach (var page in root.Children.Where("Visible"))
{
<li class="#page.IsAncestorOrSelf(Model, "current", "")">
#page.Name
</li>
}
</ul>
I just created a menu myself and needed the Home page to be active also. Working with just the method IsAncestorOrSelf doesn't work for the homepage.
The piece of code I've created is this:
#{
var root = Model.AncestorOrSelf(1);
var homeClass = root.Id == Model.Id ? "active" : "";
}
<ul id="nav" class="nav navbar-nav pull-right">
<li class="#homeClass"><a href="/" >Home</a></li>
#foreach (var page in root.Children.Where("Visible"))
{
<li class="#page.IsAncestorOrSelf(Model, "active", "")">
#page.Name
</li>
}
</ul>
This iterates through all children of the root node (1). To be able to discover if you are on the Home page, I'm checking the Id's of the page and set the active class accordingly.
Related
I made a menu for umbraco but I can't get the dropdown to work! Below is my code:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
<div class="NavDigiCampuz">
<div>
<div class="nav nav-list tree">
#{
var documentRootNodeId = Model.Content.GetPropertyValue("documentRoot", true); // Fetch recursive document root id.
var selection = Umbraco.TypedContent(documentRootNodeId).Children.Where("Visible"); // Select all nodes below the document root.
}
#foreach(var item in Model.Content.Ancestor(1).Descendants("menu")){
foreach (var Menus in #item.Descendants("menuItem")){
<li class="MenuItems">#Menus.Name</li>
foreach (var MenuItems in #Menus.Children){
if(MenuItems.GetPropertyValue("hoofdstukIcoon") != "") {
<li><a class="NormalA" href="#MenuItems.Url"><i class="fa fa-#(MenuItems.GetPropertyValue("hoofdstukIcoon")) fa-fw"></i> #MenuItems.Name</a></li>
}else {
<li><a class="NormalA"href="#MenuItems.Url">#MenuItems.Name</a></li>
var childIsActive = false;
foreach(var sub in #MenuItems.Children){
if (CurrentPage.Url == sub.Url) {
childIsActive = true;
}
<ul class="nav subnav nav-list tree #(childIsActive ? "" : "collapse")">
#foreach(var sub2 in #MenuItems.Children){
<li #(CurrentPage.Url == sub.Url ? "class=active" : "")>
<a onclick="parent.resizeParent();" href="#sub.Url">#(sub.GetPropertyValue("hoofdstukMenuTitel") != "" ? sub.GetPropertyValue("hoofdstukMenuTitel") : sub.GetPropertyValue("hoofdstukTitel"))</a>
</li>
}
</ul>
}
}
}
}
}
</ul>
</div>
</div>
</div>
The dropdown code should start at <ul class="nav subnav nav-list tree #(childIsActive ? "" : "collapse")"> but that doesn't seem to work.
Below is a quick structure of how I want my page to be:
Help item 3 should have a dropdown which it doesn't have right now. What am I missing?
You have some inconsistencies in your structure:
this line:
<div class="nav nav-list tree">
should be this:
<ul class="nav nav-list tree">
And I would remove the <div> that wrapps it.
I'm just guessing you are using something like bootstrap, are you using a framework or custom css?
Your submenu should also be nested in the <li> element:
else
{
<li><a class="NormalA" href="#MenuItems.Url">#MenuItems.Name</a>
var childIsActive = false;
foreach (var sub in #MenuItems.Children)
{
if (CurrentPage.Url == sub.Url)
{
childIsActive = true;
}
<ul class="nav subnav nav-list tree #(childIsActive ? "" : "collapse")">
#foreach (var sub2 in #MenuItems.Children)
{
<li #(CurrentPage.Url == sub.Url ? "class=active" : "")>
<a onclick="parent.resizeParent();" href="#sub.Url">#(sub.GetPropertyValue("hoofdstukMenuTitel") != "" ? sub.GetPropertyValue("hoofdstukMenuTitel") : sub.GetPropertyValue("hoofdstukTitel"))</a>
</li>
}
</ul>
}
</li>
}
I have a selection generated from the children of the current page. Within that selection (let's call it Fruit) I have items and each item has a fruitType.
This code doesn't work:
#{
var selection = CurrentPage.Children("fruit").Where("Visible");
}
<ul>
#foreach(var item in selection){
#if(#item.fruitType == "Apple"){
<li>
#item.Name<br/>
#item.fruitName<br>
#item.fruitType<br>
#if (item.image != null && !(item.image is Umbraco.Core.Dynamics.DynamicNull))
{ var m = Umbraco.Media(item.image);
<img src="#m.Url" alt="Picture of #item.Name" />
}
</li>
}
}
</ul>
What I'm trying to do is to only list the items with a fruitType of "Apple". This value is selected from a "fruitType" dropdown list and I've tried using both the numeric and string values that Umbraco uses from Dropdown datatypes.
It all works perfectly if I remove the if conditional except that it displays all fruit types.
Any suggestions?
sigh Just one too many declarations..
Turns out neither the if nor the item references need the additional # declaration in front of it so the correct code looks like:
#{
var selection = CurrentPage.Children("fruit").Where("Visible");
}
<ul>
#foreach(var item in selection){
if(item.fruitType == "Apple"){
<li>
#item.Name<br/>
#item.fruitName<br>
#item.fruitType<br>
#if (item.image != null && !(item.image is Umbraco.Core.Dynamics.DynamicNull))
{ var m = Umbraco.Media(item.image);
<img src="#m.Url" alt="Picture of #item.Name" />
}
</li>
}
}
</ul>
I want the tab to be set to active once I click on that tab (action). However, the issue I am experiencing is that the "Dashboard" tab is always set to active
<div class="row top-buffer">
<ul class="nav nav-tabs">
<li class="active">#Html.ActionLink("Dashboard", "Index")</li>
<li>#Html.ActionLink("Users", "Users")</li>
<li>#Html.ActionLink("Investigator Groups", "Groups")</li>
<li>#Html.ActionLink("Assign Games", "AssignGames")</li>
<li>#Html.ActionLink("Reports", "Reports")</li>
</ul>
</div>
Edit:
I tried doing the following, which now allows the tabs to be set to active, but no longer redirects to the action.
<li class="active" data-toggle="tab">#Html.ActionLink("Dashboard", "Index")</li>
<li data-toggle="tab">#Html.ActionLink("Users", "Users")</li>
follow this tutorial Setting the active menu item in a MVC C# Bootstrap application
by adding an extension method
public static class HtmlHelpers
{
public static string IsActive(this HtmlHelper htmlHelper, string action, string controller)
{
var routeData = htmlHelper.ViewContext.RouteData;
var routeAction = routeData.Values["action"].ToString();
var routeController = routeData.Values["controller"].ToString();
var returnActive = (controller == routeController && action == routeAction);
return returnActive ? "active" : "";
}
}
and then use it
<li class="#Html.IsActive("Index", "Dashboard")">#Html.ActionLink("Dashboard", "Index")</li>
<li class="#Html.IsActive("Users", "Users")">#Html.ActionLink("Users", "Users")</li>
I found a Grails framework for generating Breadcrumbs here. It does generate breadcrumbs based on a static definition in a breadcrumbs.xml file where it defines the hierarchies of the crumbs:
<map>
<nav id="homeCrumb" matchController="samplePages" matchAction="homeBreadCrumbPage">
<!-- levels navigation -->
<nav id="itemsLevel1Crumb" matchController="samplePages" matchAction="level1BreadCrumbPage">
<nav id="itemsLevel2Crumb" matchController="samplePages" matchAction="level2BreadCrumbPage">
<nav id="itemsLevel3Crumb" matchController="samplePages" matchAction="level3BreadCrumbPage">
<nav id="showItemCrumb" matchController="samplePages" matchAction="itemDetailsBreadCrumbPage"/>
</nav>
</nav>
</nav>
<nav id="simple1Crumb" matchController="samplePages" matchAction="simpleBreadCrumb"/>
<nav id="simple2Crumb" matchController="samplePages" matchAction="simpleBreadCrumbWithAttr"/>
<!-- levels navigation -->
</nav>
</map>
This file is evaluated and printed by a taglib:
class BreadCrumbTagLib {
static def log = LogFactory.getLog("grails.app.breadCrumbTag")
def breadCrumb = { attrs , body ->
def manager = BreadCrumbManager.getInstance()
def uri = request.getRequestURI()
def context = request.getContextPath()
def controller = params.controller
def action = params.action
def attrTitle = attrs.title
def attrLink = attrs.link
// if controller and action are missing from params try to get them from request url
if (!controller && !action && uri && context && uri.indexOf(context) != -1) {
def uriParams = uri.substring(uri.indexOf(context) + (context.length() + 1), uri.length())
def uriArray = uriParams.split('/')
if (uriArray.size() >= 2 ) {
controller = uriArray[0]
action = uriArray[1]
}
}
def crumbs = manager.getBreadCrumbs(controller, action)
if (crumbs) {
out << '<div class="breadcrumb"><ul>'
def size = crumbs.size()
crumbs.eachWithIndex { crumb, index ->
out << '<li>'
// override title and link of breadcrumb on current page (i.e. last bread crumb in hierarchy)
// if name, link attributes are supplied
if (index == size - 1) {
if (attrTitle)
crumb.title = attrTitle
if (attrLink)
crumb.link = attrLink
}
// set title to undefined if not found, associated
// renderer if present can overwrite it
if (!crumb.title)
crumb.title = "undefined"
if (crumb.title && crumb.title.size() > 40)
crumb.title = crumb.title.substring(0, 40) + "..."
if (crumb.viewController && crumb.viewAction) {
def content = g.include(controller:crumb.viewController, action:crumb.viewAction, breadcrumb:crumb, params:params)
out << content
} else if (crumb.viewTemplate) {
def content = g.include(view:crumb.viewTemplate, breadcrumb:crumb, params: params)
out << content
} else if (crumb.linkToController && crumb.linkToAction && (size - 1 > index)){
out << "${crumb.title}"
// if crumb has a link and its not the last vread crumb then show link else
// just show the text
} else if (crumb.link && (size - 1 > index)){
out << "${crumb.title}"
} else {
out << "${crumb.title}"
}
out << "</li>"
// do not print for last bread crumb
if (size - 1 > index)
out << "<li>ยป</li>"
}
out << "</ul></div>"
}
}
}
Problem: When I have a structure where I need some params which are not fix.
Example: I am in the third level of navigation lets say
A1 / A2 / A3
In my case A2 should open a page like user/show/1234 where 1234 is the id of the user to show. The problem is that I cannot add 1234 hard coded in the breadcrumbs.xml file because this id changes depending on which user you want to show.
How can I handle this when an intermediate breadcrumbs link needs dynamic parameters?
After thinking about it some more, I realized it may be better not to use the HttpSession. If you use a session-scoped service instead it will be easier to unit test the breadcrumb code.
First, create a session-scoped service to maintain the user's navigation history.
class NavigationHistoryService {
static transactional = false
static scope = "session"
def history = [:]
public List push(String controller, String action, Map params) {
def crumb = [
action: action,
params: params]
history.controller = crumb
return history
}
In your controllers inject the service and use it to keep track of where the user has been. Then add the history as part of what's returned by the action's model:
class CompanyController {
def navigationHistoryService
def show() {
navigationHistoryService.push('company', 'show', params)
...
[crumbs: navigationHistoryService.history]
}
}
Finally, use the history in your GSP to render the crumbs.
<ol class="breadcrumb">
<li><g:link controller="company" action="${crumbs.company.action}" params="${crumbs.company.params}">SOMETHING</a></li>
</ol>
It looks like your breadcrumbs are in the format CONTROLLER/ACTION/ID. If that's so, the information you need is already available in your GSP via the webRequest property. Here's an example using Twitter Bootstrap breadcrumbs:
<ol class="breadcrumb">
<li>${webRequest.controllerName}</li>
<li>${webRequest.actionName}</li>
<li class="active">${webRequest.id}</li>
</ol>
You'd still have to set up the hrefs to something meaningful. A more robust approach would be something like this...
<g:set var="crumbs" value="${[webRequest.controllerName, webRequest.actionName, webRequest.id].findAll { it != null }}.collect { [label: it, active: false] }" />
<% crumbs.last().active = true %>
<ol class="breadcrumb">
<g:each in="${crumbs}">
<li class="${it.active ? 'active' : ''}">${it.label}</li>
</g:each>
</ol>
Embedding Groovy code into GSP via the <% %> tags is not recommended, but something like this could be done in a TagLib. This approach can handle breadcrumbs of 1-3 parts in length. It adjusts according to the current URI.
use simple by blade view
<ul class="breadcrumb" style="padding-right: 20px">
<li> <i class="fa fa-home"></i> <a class="active" href="{{url('/')}}">Home</a>
{{--<i class="fa fa-angle-right"></i>--}}
</li> <?php $link = url('/') ; ?>
#for($i = 1; $i <= count(Request::segments()); $i++)
<li>
#if($i < count(Request::segments()) & $i > 0)
<?php $link .= "/" . Request::segment($i); ?>
<a class="active" href="<?= $link ?>">{{Request::segment($i)}}</a>
{{--{!!'<i class="fa fa-angle-right"></i>'!!}--}}
#else {{Request::segment($i)}}
#endif
</li>
#endfor
</ul>
I'm trying to create a razor menu in umbraco with a razor macro. I followed the umbraco tutorial about creating a razor menu:
http://umbraco.com/help-and-support/video-tutorials/umbraco-fundamentals/razor-recipes/navigation/TVPlayer
It works for my first three pages but then I want to add another one but the page doesn't show up in my menu. I have the following structure for my pages:
Start, calendar and Foto's do show up in my menu, but the news page doesn't. Is this structure correct or do I have to create a 'Home' page and place all my pages under that?
This is my razor macro code:
#inherits umbraco.MacroEngines.DynamicNodeContext
<nav>
<ul>
#{ var homeNode = Model.AncestorOrSelf("Home"); }
<li>#homeNode.Name</li>
#foreach (var page in homeNode.Children.Where("Visible"))
{
var isSelected = false;
if (Model.Id == page.Id || (Model.Parent != null && Model.Parent.Id == page.Id && Model.NodeTypeAlias != "Textpage"))
{
isSelected = true;
}
<li>
#page.Name
<!-- If the page has child nodes (2nd level) that are visible and docTypeAlias is Textpage (textpages) -->
#if (page.Children.Where("Visible").Count() > 0)
{
<ul>
#foreach (var childPage in page.Children.Where("Visible"))
{
<li>
#childPage.Name
</li>
}
</ul>
}
</li>
}
</ul>
</nav>
Ideally yes you need a page made with a doc type with the alias "Home" as you are defining you starting node/var by getting that page here,
var homeNode = Model.AncestorOrSelf("Home");
then after you are getting all the child pages of this homeNode so really all your structure should be
content
- Home
- start
- calender
- frontpage sliders
- fotos
- news