Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Umbraco Newbie 22 posts 124 karma points
    Jan 14, 2017 @ 09:32
    Umbraco Newbie
    0

    Breadcrumb using c# class

    Hi

    I currently have the following for creating breadcrumbs:

    @inherits UmbracoTemplatePage
    
    <div class="breadcrumbs-block">
        @{
            var selection = CurrentPage.Ancestors();
            if (selection.Any())
            {
                <ul class="breadcrumb">
    
                    @foreach (var item in selection.OrderBy("Level"))
                    {
                        <li><a href="@item.Url">@item.Name</a> <span class="divider"></span></li>
                    }
                    <li>@CurrentPage.Name</li>
                </ul>
            }
        }
    </div>
    

    What I want is to move the above code and put it into a .cs class so that the partial that contains the above will look something like:

    @using Web.Model.Breadcrumbs
    
    <div class="breadcrumbs-block">
        @{
            <ul class="breadcrumb">
    
                    @foreach (var item in breadcrumbs)
                    {
                        <li><a href="@item.Url">@item.Name</a> <span class="divider"></span></li>
                    }
                    <li>Breadcrumbs.Name</li>
                </ul>
            }
        }
    </div>
    

    Problem is I just cannot get it to work, my last attempt was:

    namespace Web.Model.Breadcrumbs
    {
        public class test
        {
            public string tests()
            {
                IPublishedContent content = null;
                var yy = content.Children.DescendantsOrSelf("-1").Select(x => x.Ancestors());
                return null;
            }
        }
        public class WebsiteBreadcrumbs
        {
    
    
            public string SiteBreadcrumbs()
            {
                var test = new UmbracoHelper();
            var selection = test.Ancestors().ToList();
    
    
    
                StringBuilder sb = new StringBuilder();
                if (selection.Any())
                {
                    sb.Append("<ul>");
                    foreach (var links in selection)
                    {
                        sb.AppendLine("<li>" + links + "</li>");
                    }
                    sb.Append(CurrentPage.Name);
                    sb.Append("/ul>");
                }
    
    
                return "test";
                //}
            }
        }
    }
    

    All the above fail, can any help with this Thanks George

  • Alex Skrypnyk 6163 posts 24143 karma points MVP 8x admin c-trib
    Jan 14, 2017 @ 10:24
    Alex Skrypnyk
    0

    Hi George,

    Where did you put this class?

    What error exactly do you have?

    Is UmbracoHelper accessible from this class?

    We will fix it together :)

    Thanks,

    Alex

  • Umbraco Newbie 22 posts 124 karma points
    Jan 14, 2017 @ 11:20
    Umbraco Newbie
    0

    Hi Alex

    No error, value is always null. Class is in another class library that has umbraco core installed.

    Thanks George

  • Nik 1614 posts 7260 karma points MVP 7x c-trib
    Jan 14, 2017 @ 12:01
    Nik
    101

    Hi George,

    Before we get into this, why aren't you happy with the Partial View that you have? When else are you going to need the "breadcrumbs"?

    Personally, I think what you currently have works pretty well for a breadcrumb process. You can simply call the your partial view on any page and it will work.

    Looking at your code, you've got a bit of conflicting code present, in addition, you never pass in your current page anywhere as a result the breadcrumbs have nowhere to identify what they are doing.

    If you modify your "WebsiteBreadcrumbs" class as follows:

    public static class WebsiteBreadcrumbs
    {
    
        public string SiteBreadcrumbs(IPublishedContent currentPage)
        {
    
            var selection = currentPage.Ancestors().ToList();
    
            StringBuilder sb = new StringBuilder();
            if (selection.Any())
            {
                sb.Append("<ul>");
                foreach (var links in selection)
                {
                    sb.AppendLine("<li>" + links + "</li>");
                }
                sb.Append(currentPage.Name);
                sb.Append("/ul>");
            }
    
    
            return sb.ToString();
    
        }
    }
    

    You can then call WebsiteBreadcrumbs.SiteBreadCrumbs(Model.Content) on any template that inherits from UmbracoTemplatePage and it should give you an output. Assuming that Model.Content is not null.

    Nik

  • Umbraco Newbie 22 posts 124 karma points
    Jan 15, 2017 @ 12:44
    Umbraco Newbie
    0

    Hi Nik

    The reason I wanted the code in .cs file was I learning Umbraco and thought there must be another way.

    Just experimenting :)

    Regards George

  • Damiaan 442 posts 1302 karma points MVP 6x c-trib
    Jan 17, 2017 @ 21:21
    Damiaan
    0

    Nik tells the truth. Partials rock! :)

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Mar 16, 2018 @ 15:25
    Ronald Barendse
    3

    The easiest partial view could even look like this:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage
    <ul>
        @foreach (var content in Model.Ancestors().Reverse())
        {
            <li><a href="@content.Url">@content.Name</a></li>
        }
        <li>@Model.Name</li>
    </ul>
    

    No StringBuilders or custom classes needed! ;-)

  • Harry Spyrou 212 posts 604 karma points
    Aug 21, 2018 @ 11:07
    Harry Spyrou
    1

    I used Ronald's simple breadcrumbs navigation and I ran into a problem because in the design I have, they are supposed to be in Nested Content and 'Model' in NC means nothing. So I did this:

        @inherits Umbraco.Web.Mvc.UmbracoViewPage
    
    @{ 
        var currentPageId = Umbraco.UmbracoContext.PageId;
        var currentPage = Umbraco.Content(currentPageId);
    }
    
        @foreach (var content in currentPage.Ancestors().Reverse())
        {
            <a class="breadcrumb" href="@content.Url">
                @content.Name
            </a>
        }
        <span class="breadcrumb">@currentPage.Name</span>
    

    Now, the breadcrumbs don't actually care if Model is there or not. They will just pick up the current document type and let you work your magic.

  • Nik 1614 posts 7260 karma points MVP 7x c-trib
    Aug 21, 2018 @ 11:30
    Nik
    0

    Hi Harry,

    Although this works, you shouldn't really be doing it this way. The use of Umbraco.Content results in a dynamic object being returned and this isn't advised any more. You also have an unnecessary step in your code, I believe you could simplify this as follows:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage
    
    @foreach(var content in Umbraco.AssignedContentItem.Ancestors().Reverse())
    {
          //put your rendering code here
    
    }
    
    <span class="breadcrumb">@Umbraco.AssignedContentItem.Name</span>
    

    I've not tested this fully, but the premise behind it is that AssignedContentItem (it might be AssignedContent, I can't remember) should already have your current page as an IPublishedContent item. You can then use this to get ancestors, and do the reverse of the enumerable it results in. This saves you getting the ID from context and then getting the dynamic object from the Umbraco helper.

    Cheers

    Nik

  • Harry Spyrou 212 posts 604 karma points
    Aug 21, 2018 @ 11:37
    Harry Spyrou
    0

    Hi Nik,

    It doesn't work, but let me test it a little bit more, since I didn't notice the dynamic object you were talking about. Thanks for that.

    Harry

  • Harry Spyrou 212 posts 604 karma points
    Aug 21, 2018 @ 11:49
    Harry Spyrou
    0

    Hi Nik,

    You were right about the dynamic object being returned, but your code had the same problem as the first breadcrumbs (looking into nested content instead of the actual document type/page).

    So instead of returning a dynamic object I changed:

    var currentPage = Umbraco.Content(currentPageId);
    

    to:

    var currentPage = Umbraco.TypedContent(currentPageId);
    

    And now it returns IPublishedContent

    Thanks for the help! Cheers!

    Final code is:

    @inherits Umbraco.Web.Mvc.UmbracoViewPage
    
    @{ 
        var currentPageId = Umbraco.UmbracoContext.PageId;
        var currentPage = Umbraco.TypedContent(currentPageId);
    }
    
        @foreach (var content in currentPage.Ancestors().Reverse())
        {
            <a class="breadcrumb" href="@content.Url">@content.Name ></a>
        }
        <span class="breadcrumb">@currentPage.Name</span>
    

    P.S. If you see anything else wrong in my code, please let me know.

  • Arnel Gajek 5 posts 95 karma points
    Jun 26, 2019 @ 11:41
    Arnel Gajek
    0

    Hi Ronald,

    How does it work if you have a tree that looks like this:

    • Start
      • Child
        • Grandchild

    Does the foreach loop go through the grandchild so that you can pass the .Name for the content all the way down?

    Br, Arnel Gajek

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 26, 2019 @ 11:50
    Ronald Barendse
    1

    Not sure what you mean with 'pass the .Name for the content all the way down', but it just gets all ancestors (if you're currently on 'Grandchild', that would be 'Child' and 'Start'), reverses it (so you get 'Start' and then 'Child') and then renders a link for every ancestor (as these are IPublishedContent, you can just use the Name and Url properties).

  • Arnel Gajek 5 posts 95 karma points
    Jun 26, 2019 @ 11:57
    Arnel Gajek
    0

    The thing is that we have a parent (Start) that has a child (Aktiviteter) and a grand child (Frukostmöten). The child and the grand child uses the same template (defaultpagetemplate), but the bread crumbs only works at the child and not the grand child. Any ideas on how to solve this?

    BTW I'm using Umbraco v.8.

    Br, Arnel Gajek

    enter image description here

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 26, 2019 @ 12:09
    Ronald Barendse
    0

    If nothing is rendered, you probably have a condition somewhere that just prevents it from executing... Otherwise, when using Umbraco 8 and especially with culture variants, it might even be a bug in how the ancestors are fetched...

  • Arnel Gajek 5 posts 95 karma points
    Jun 26, 2019 @ 12:13
    Arnel Gajek
    0

    I have one section on the website where the bread crumbs works on the grand child as well. The thing that stands out here is that the grand child doesn't have the same template as the other grand childs (defaultpagetemplate). Could it be that I need to use a different template for the grand children to make this work?

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 26, 2019 @ 12:27
    Ronald Barendse
    0

    @nik Umbraco.AssignedContentItem doesn't work inside partials rendering Nested Content items, but UmbracoContext.PublishedContentRequest.PublishedContent does get the current page.

    Not sure why you would have a NC item for rendering the breadcrumb, as you probably want to have it on a fixed place in the site and don't want editors forget adding it, moving it to a different place or even add multiple breadcrumbs to a page...

  • Bahadur 7 posts 78 karma points
    Oct 14, 2019 @ 10:17
    Bahadur
    0

    This is the best solution ever!

  • Paul Seal 524 posts 2889 karma points MVP 7x c-trib
    Aug 21, 2018 @ 13:07
    Paul Seal
    1

    I personally like to create an Html Helper class which I can call from wherever I want like this

    @Html.Breadcrumb(Model.Content)
    

    Here is the code I like to use:

    using System.Collections.Generic;
    using System.Text;
    using System.Web;
    using System.Web.Mvc;
    using Umbraco.Core.Models;
    using Umbraco.Web;
    
    namespace CodeShare.Library.Helpers.General
    {
        public static class HtmlExtensions
        {
            public static IHtmlString Breadcrumb(this HtmlHelper helper, IPublishedContent thisPage)
            {
                StringBuilder breadcrumb = new StringBuilder();
    
                IEnumerable<IPublishedContent> ancestors = thisPage.Ancestors().Reverse();
    
                foreach(IPublishedContent page in ancestors)
                {
                    breadcrumb.Append($"<a href=\"{page.Url}\">{page.Name}</a>");
                }
    
                breadcrumb.Append($"<span>{thisPage.Name}</span>");
    
                return MvcHtmlString.Create(breadcrumb.ToString());
            }
        }
    }
    

    I wrote a blog post about it. You can read it here: https://codeshare.co.uk/blog/how-to-create-a-custom-html-helper-extension-method-in-mvc-and-umbraco/

  • Harry Spyrou 212 posts 604 karma points
    Aug 21, 2018 @ 13:54
    Harry Spyrou
    1

    Hi paul,

    Big fan of your work by the way since I basically learned how to use Umbraco from your tutorials.

    I like the extension, but the boss has decided that we're going on a view only kind of approach since we have a lot of time pressuring us. I'm definitely going to use it at some point later on though. Thanks for the reply.

    Cheers, Harry

  • George Phillipson 108 posts 287 karma points
    Jun 26, 2019 @ 12:02
    George Phillipson
    0

    This works for me in a partial view

    @inherits UmbracoViewPage
    @{
        var selection = Model.Ancestors().ToList();
        int counter = 1;
    
        if (selection.Any())
        {  
            <nav id="nav-breadcrumbs" class="container" aria-label="Breadcrums Navigation">
                <ol itemscope itemtype="http://schema.org/BreadcrumbList" class="breadcrumb">
                    @foreach (var item in selection.OrderBy(x => x.Level))
                    {
                        <li class="breadcrumb-item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
                            <a itemprop="item" href="@item.Url"><span itemprop="name">@item.Name</span></a>
                            <meta itemprop="position" content="@counter" />
                        </li>
                    }
                    <li class="breadcrumb-item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
                        <span itemprop="name">@Model.Name</span>
                        <meta itemprop="position" content="@counter" />
                    </li>
                </ol>
            </nav>
        }
    
    }
    

    Regards George

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 26, 2019 @ 12:06
    Ronald Barendse
    0

    What's the use for counter if it is always 1? And why use OrderBy(x => x.Level), if you can just reverse all items?

    The addition of microdata is a good one though!

  • George Phillipson 108 posts 287 karma points
    Jun 26, 2019 @ 12:15
    George Phillipson
    1

    Hi Ronald

    I deleted some code and took out the counter++ by mistake

    when added back inside foreach it returns

    <nav id="nav-breadcrumbs" class="container" aria-label="Breadcrumbs Navigation">
                <ol itemscope="" itemtype="http://schema.org/BreadcrumbList" class="breadcrumb">
                        <li class="breadcrumb-item" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
                            <a itemprop="item" href="/"><span itemprop="name">Home</span></a>
                            <meta itemprop="position" content="1">
                        </li>
                        <li class="breadcrumb-item" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
                            <a itemprop="item" href="/blogs/"><span itemprop="name">Blogs</span></a>
                            <meta itemprop="position" content="2">
                        </li>
                        <li class="breadcrumb-item" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
                            <a itemprop="item" href="/blogs/asp-net/"><span itemprop="name">ASP.NET</span></a>
                            <meta itemprop="position" content="3">
                        </li>
                    <li class="breadcrumb-item" itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem">
                        <span itemprop="name">Using enum in a switch case</span>
                        <meta itemprop="position" content="4">
                    </li>
                </ol>
            </nav>
    

    and if you read https://schema.org/itemListElement it explains about the position

    I used 'Level' as this code is for Umbraco 8 and was written when I was playing about, Umbraco.TypedContent does not work in V8 as it returns:

    UmbracoHelper' does not contain a definition for 'TypedContent' and no accessible extension method 'TypedContent' accepting a first argument of type 'UmbracoHelper'

  • Ronald Barendse 39 posts 218 karma points hq c-trib
    Jun 26, 2019 @ 12:33
    Ronald Barendse
    0

    You only need the Ancestors() method on the model (as that's the currently rendered page) and reverse the order...

    Umbraco 8 removed dynamics, so they changed Umbraco.TypedContent() back to Umbraco.Content(), that's all!

  • George Phillipson 108 posts 287 karma points
    Jun 26, 2019 @ 12:50
    George Phillipson
    0

    Hi Ronald

    Learn something new every day, did not know it had been changed back

    Regards George

    If anyone wants the code I have put it below

    @inherits UmbracoViewPage
    @{
        var selection = Model.Ancestors().Reverse().ToList();
        int counter = 1;
    
        if (selection.Any())
        {  
            <nav id="nav-breadcrumbs" class="container" aria-label="Breadcrumbs Navigation">
                <ol itemscope itemtype="http://schema.org/BreadcrumbList" class="breadcrumb">
                    @foreach (var item in selection)
                    {
                        <li class="breadcrumb-item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
                            <a itemprop="item" href="@item.Url"><span itemprop="name">@item.Name</span></a>
                            <meta itemprop="position" content="@counter" />
                        </li>
                        counter++;
                    }
                    <li class="breadcrumb-item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">
                        <span itemprop="name">@Model.Name</span>
                        <meta itemprop="position" content="@counter" />
                    </li>
                </ol>
            </nav>
        }
    
    }
    

    I'm using var selection = Model.Ancestors().Reverse().ToList(); as Resharper complains about 'possible muliple enumeration' without the ToList()

Please Sign in or register to post replies

Write your reply to:

Draft