2

I'm trying to use a sitecore navigation sublayout. Right now I am using 2 different ones. One is used on the parent item and it pulls all of the child items. The other is used on the child items, that just pulls its siblings. I want to use one layout that pulls the parent, child and siblings. The 2 I'm using now is not displaying the Self or Parent item. Here is my code use on the parent

<script runat="server">
void Page_Load(object sender, System.EventArgs e) {
DataBind();
}

IEnumerable<Sitecore.Data.Items.Item> SubItems
{
get { 
    return Sitecore.Context.Item.Children;

    }
}
</script>
<nav class="section">
<asp:Repeater ID="repSubItems" runat="server" DataSource="<%# SubItems%>">
<HeaderTemplate>
  <ul>

   </HeaderTemplate>
  <ItemTemplate>
  <li>
  <a href="<%# Sitecore.Links.LinkManager.GetItemUrl(Container.DataItem as Sitecore.Data.Items.Item) %>">
    <sc:FieldRenderer FieldName="Navigation Title" runat="server" Item="<%# Container.DataItem as Sitecore.Data.Items.Item %>" />
    </a>
   </li>
   </ItemTemplate>
  <FooterTemplate>
  <ul>
  </FooterTemplate>
 </asp:Repeater>
  </nav>

and the nav for the child items pulling siblings

<nav class="section">
  <asp:Repeater runat="server" ID="navRepeater">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
    <li>
        <asp:HyperLink runat="server" id="navLink"/>
    </li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
</nav>

code behing for that one

namespace Layouts.Nav_inner_prog {


 public partial class Nav_inner_progSublayout : System.Web.UI.UserControl 
  {
    protected void Page_Load(object sender, EventArgs e)
    {
        var parent = Sitecore.Context.Item.Parent;

        navRepeater.DataSource = parent.Children;
        navRepeater.ItemDataBound += navRepeater_ItemDataBound;
        navRepeater.DataBind();
    }

    private void navRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
        {
            var item = e.Item.DataItem as Sitecore.Data.Items.Item;
            var navLink = e.Item.FindControl("navLink") as HyperLink;

            if (item.ID == Sitecore.Context.Item.ID)
            {
                if (navLink.CssClass.Length > 0)
                {
                    navLink.CssClass += " ";
                }
                navLink.CssClass += "selected";
            }

            navLink.Text = item.DisplayName;
            navLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(item);
        }
    }
  }
 }
Jonathan Robbins
  • 2,027
  • 1
  • 16
  • 30
  • To clarify you want a Single Ascx that you can put on both Parent and Child Items that will always display the Parent and Self? – Jonathan Robbins Jul 23 '15 at 11:36
  • If the sublayout is used on the parent I want it to display Self and child items, if its used on the child items, then siblings and Parent. – Matthew Loeffler Jul 23 '15 at 11:47

1 Answers1

1

In my opinion, I would change your approach and align with Sitecore's best practices and use Datasources to achieve this.

In Sitecore when you add the Sublayout to the Presentation Details add the Datasource to the Item you want to act as the "Parent" Item. Then use the following code

<asp:Repeater runat="server" ID="NavigationRepeater" ItemType="Sitecore.Data.Items.Item" OnItemDataBound="NavigationRepeater_OnItemDataBound">
    <HeaderTemplate>
        <a href="<%# GetUrl(ParentItem) %>">
            <sc:FieldRenderer FieldName="Navigation Title" runat="server" Item="<%# ParentItem %>" />
        </a>
    </HeaderTemplate>
    <ItemTemplate>
        <asp:HyperLink runat="server" id="navLink"/>
    </ItemTemplate>
</asp:Repeater>

Then the code behind as follows

public Sitecore.Web.UI.WebControls.Sublayout Sublayout
        {
            get
            {
                return Parent as Sitecore.Web.UI.WebControls.Sublayout;
            }
        }

        private Item _parentItem;
        public Item ParentItem
        {
            get
            {
                if (_parentItem == null)
                {
                    if (!string.IsNullOrEmpty(Sublayout.DataSource))
                    {
                        Item dbItem = Sitecore.Context.Database.GetItem(Sublayout.DataSource);

                        if (dbItem != null)
                        {
                            _parentItem = dbItem;
                        }
                    }
                }

                return _parentItem;
            }
        }

        public IEnumerable<Sitecore.Data.Items.Item> SubItems
        {
            get
            {
                return ParentItem != null ? ParentItem.Children : new List<Item>();
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                BindNavigation();
            }
        }

        public string GetUrl(Item item)
        {
            return item != null ? Sitecore.Links.LinkManager.GetItemUrl(item) : string.Empty;
        }

        private void BindNavigation()
        {
            NavigationRepeater.DataSource = SubItems;
            NavigationRepeater.DataBind();
        }

        protected void NavigationRepeater_OnItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            if (e.Item.ItemType == ListItemType.AlternatingItem || e.Item.ItemType == ListItemType.Item)
            {
                var item = e.Item.DataItem as Sitecore.Data.Items.Item;
                var navLink = e.Item.FindControl("navLink") as HyperLink;

                if (item.ID == Sitecore.Context.Item.ID)
                {
                    if (navLink.CssClass.Length > 0)
                    {
                        navLink.CssClass += " ";
                    }
                    navLink.CssClass += "selected";
                }

                navLink.Text = item.DisplayName;
                navLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(item);
            }
        }

If you do have to go against best practice you need a away to differentiate a SubItem from a Parent Item. This could be done via differnt ItemTemplates of the Item and checking for the TemplateId or even a checkbox field on the Parent Item. Examples of both are shown below respectfully;

private Item _parentItem;
public Item ParentItem
{
    get
    {
        if (_parentItem == null)
        {
            if (Sitecore.Context.Item.TemplateID == new ID("GUID OF PARENT ITEM TEMPLATE"))
            {
                _parentItem = Sitecore.Context.Item;
            }
            else
            {
                // Else set the parent of context Item to be the parent
                // Assuming you don't want a grandparent or other ancestor
                // being the parent as the wrong child will be shown
                _parentItem = Sitecore.Context.Item.Parent;
            }
        }

        return _parentItem;
    }
}
private Item _parentItem;
public Item ParentItem
{
    get
    {
        if (_parentItem == null)
        {
            if (Sitecore.Context.Item.Fields["Navigation Parent"] != null
                && Sitecore.Context.Item.Fields["Navigation Parent"].Value == "1")
            {
                _parentItem = Sitecore.Context.Item;
            }
            else if (Sitecore.Context.Item.Parent.Fields["Navigation Parent"] != null
                && Sitecore.Context.Item.Parent.Fields["Navigation Parent"].Value == "1")
            {
                _parentItem = Sitecore.Context.Item.Parent;
            }
            else
            {
                // Assuming you don't want an ancestor's child to be displayed
                _parentItem = null;
            }
        }

        return _parentItem;
    }
}
Jonathan Robbins
  • 2,027
  • 1
  • 16
  • 30
  • Object reference not set to an instance of an object. Line 51: get Line 52: { Line 53: return ParentItem.Children; Line 54: //return Sitecore.Context.Item.Children; Line 55: } – Matthew Loeffler Jul 23 '15 at 14:00
  • The parent Item is null in this case. Ensure you have added a datasource, or have Item with a parent template orItem with the Navigation parent checkbox checked. I'll update the code to handle the parent item being empty now – Jonathan Robbins Jul 23 '15 at 14:34
  • Also fixed a bug in the code you wrote that caused a null exception, in stead of getting the Link for the Item on the front-end its passed to the code behind to complete a null check before getting it – Jonathan Robbins Jul 23 '15 at 14:56
  • I can seem to get any of your code to work. Do you have just a basic working example. the code behind calls out for subItems but I dont see any in ascx file – Matthew Loeffler Jul 23 '15 at 16:55
  • It looks like when I copied the SubItems code from your existing ascx I didn't add a public to it so it could be accessed. SubItems is defined in the second block of code, just under ParentItem – Jonathan Robbins Jul 23 '15 at 17:00