This is post 2 of 5 in a series titled Patterns for navigation controls
- Patterns for navigation controls - Basics
- Patterns for navigation controls - Breadcrumbs
- Patterns for navigation controls - Varied styles
- Patterns for navigation controls - Language versions
- Patterns for navigation controls - Language trees
Last week I started looking at some simple ideas for the top level navigation for Sitecore websites. This week, I'll continue that theme with some simple examples of the more localised navigation that you might use on content pages.
It is fairly simple to achieve. Simple mark-up might look like:
<div> <asp:Repeater runat="server" ID="breadcrumbRepeater"> <ItemTemplate> <span runat="server" id="divider"> > </span> <asp:HyperLink runat="server" ID="breadcrumbLink" /> </ItemTemplate> </asp:Repeater> </div>
and the code-behind would be:
protected void Page_Load(object sender, EventArgs e) { var rootItem = Sitecore.Context.Database.GetItem(Sitecore.Context.Site.ContentStartPath); var ancestors = Sitecore.Context.Item .Axes.GetAncestors() .Where(i => !i.Axes.IsAncestorOf(rootItem)); breadcrumbRepeater.DataSource = ancestors; breadcrumbRepeater.ItemDataBound += breadcrumbRepeater_ItemDataBound; breadcrumbRepeater.DataBind(); } private void breadcrumbRepeater_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 breadcrumbLink = e.Item.FindControl("breadcrumbLink") as HyperLink; var divider = e.Item.FindControl("divider") as HtmlGenericControl; if(e.Item.ItemIndex == 0) { divider.Visible = false; } breadcrumbLink.Text = item.DisplayName; breadcrumbLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(item); } }
As with last week's examples, we use the
Sitecore.Context.Site.ContentStartPath
property to find the item in your content tree which represents the root of the current site. The ancestor items for the current page can then be computed by asking Sitecore for the page's set of ancestors, and filtering out any of those pages which is not an ancestor of the root item. That leaves you with a collection of items to display.
The display can be achieved with a simple data binding to a repeater. The one important thing to remember here is that you usually have some sort of "divider" character between each item in your breadcrumb list. It's possible to do this via CSS or via code, but since I'm generally skipping over the CSS aspects of the UI in these examples, I've done it via code above. The mark-up includes a
<span>
element to contain the divider character. This is marked as
runat="server
so that it can be enabled and disabled in the code-behind. When the data binding is processed for each item, the code checks if the index for the item being processed is zero (ie "is this the first item in your data list"). If so, it hides the divider.
A basic secondary navigation could start from the following mark-up:
<asp:Repeater runat="server" ID="navRepeater"> <HeaderTemplate><ul></HeaderTemplate> <ItemTemplate> <li> <asp:HyperLink runat="server" id="navLink"/> </li> </ItemTemplate> <FooterTemplate></ul></FooterTemplate> </asp:Repeater>
and code behind:
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 += "currentNavItem"; } navLink.Text = item.DisplayName; navLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(item); } }
The code finds the parent item of the current page, and uses its children as the data source for the repeater. For each item that it renders in the repeater, it checks if its ID matches the ID of the current page. If it does, then it adds an extra CSS class to allow the item to be displayed with a "this is the current page" style. Note that the code won't work if you try to compare the these two
Item
instances directly - as that would be a reference comparison. Comparing the IDs is a value comparison, and hence will be a valid test if the two classes represent the same content item.
A bit more nav related stuff next week, I think...
↑ Back to top