+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Displaying the Categories Assigned to a Sitefinity Content Item as Clickable Links

by Boyan Barnev
Many of you have used our Taxonomy Fields for displaying the taxa an item's marked with on the frontend. We've received some feedback form clients that in certain cases you'd prefer to have this list of taxa behave as clickable taxonomy links, which when clicked can dynamically filter the ListView control.

As you know, by default the Hierarchical/FlatTaxonField when in Read mode will output the list of taxa names, as a clear text. For today's blog post we'll see how we can customize the way the taxa are displayed, and achieve filtering functionality.

We are going to adopt the good old approach of using an external widget template. This approach has many benefits. First, it allows us to easily add a code-behind to any template, and implement the additional business logic. Second, since all ContentView-based widgets use a databound control, like RadListView for displaying the list of items on the frontend, we could easily subscribe to the ItemDataBound event of the list view, and get access to each item that gets bound, and to its properties.

For the current blog post, let's take the News widget for example. We can copy its default template for TitlesDatesSummariesListView and paste the HTML in a new UserControl.

Then, while still on the presentational part, we can define a placeholder to display our category links. For example a label:

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="TitlesDatesSummariesListViewCategoryLinks.ascx.cs" Inherits="SitefinityWebApp.CustomTemplates.News.Frontend.TitlesDatesSummariesListViewCategoryLinks" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.ContentUI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.Comments" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI" Assembly="Telerik.Sitefinity" %>
<%@ Register TagPrefix="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI" %>
<%@ Register TagPrefix="sf" Namespace="Telerik.Sitefinity.Web.UI.PublicControls.BrowseAndEdit" Assembly="Telerik.Sitefinity" %>
 
<telerik:RadListView ID="NewsList" ItemPlaceholderID="ItemsContainer" runat="server" EnableEmbeddedSkins="false" EnableEmbeddedBaseStylesheet="false">
    <LayoutTemplate>
        <sf:ContentBrowseAndEditToolbar ID="MainBrowseAndEditToolbar" runat="server" Mode="Add"></sf:ContentBrowseAndEditToolbar>
        <ul class="sfnewsList sfnewsListTitleDateSummary">
            <asp:PlaceHolder ID="ItemsContainer" runat="server" />
        </ul>
    </LayoutTemplate>
    <ItemTemplate>
        <li class="sfnewsListItem">
            <h2 class="sfnewsTitle">
                <sf:DetailsViewHyperLink ID="DetailsViewHyperLink1" TextDataField="Title" ToolTipDataField="Description" runat="server" />
            </h2>
            <div class="sfnewsMetaInfo">
                <sf:FieldListView ID="PublicationDate" runat="server" Format="{PublicationDate.ToLocal():MMM dd, yyyy}" />
            </div>
 
            <sf:FieldListView ID="summary" runat="server" Text="{0}" Properties="Summary" WrapperTagName="div" WrapperTagCssClass="sfnewsSummary"  />
 
            <sf:DetailsViewHyperLink ID="FullStory" Text="<%$ Resources:NewsResources, FullStory %>" runat="server" CssClass="sfnewsFullStory" />
            <br /><sf:SitefinityLabel Id="CategoriesLabel" runat="server"></sf:SitefinityLabel>
            <sf:ContentBrowseAndEditToolbar ID="BrowseAndEditToolbar" runat="server" Mode="Edit,Delete,Unpublish"></sf:ContentBrowseAndEditToolbar>
        </li>
    </ItemTemplate>
</telerik:RadListView>
<sf:Pager id="pager" runat="server"></sf:Pager>
<asp:PlaceHolder ID="socialOptionsContainer" runat="server" />

Then we can move to our new UserControl's code-behind part, to implement our business logic.

First, we need to subscribe to the ItemDataBound event of our RadListView control:
protected void Page_Load(object sender, EventArgs e)
       {
           //subscribe to the ItemDataBound event of the RadListView control that displays the news items
           NewsList.ItemDataBound += new EventHandler<Telerik.Web.UI.RadListViewItemEventArgs>(NewsList_ItemDataBound);
       }

Next we have to get the actual Sitefinity content item that is being passed as parameter to the ItemDataBound event:
void NewsList_ItemDataBound(object sender, Telerik.Web.UI.RadListViewItemEventArgs e)
       {
           switch (e.Item.ItemType)
           {
               case RadListViewItemType.DataItem:
               case RadListViewItemType.AlternatingItem:
                   var listViewDataItem = (RadListViewDataItem)e.Item;
                   //get the actual news item that's currently bound to the ListView
                   var dataItem = (NewsItem)listViewDataItem.DataItem;

We also need to get a reference to our control that is going to display the desired categories links, and set its value:
if (dataItem != null)
                    {
                        //get our control that displays the Categories
                        var placeholder = e.Item.FindControl("CategoriesLabel") as SitefinityLabel;
                        //and render the categories as clickable links
                        placeholder.Text = RenderHierarchicalTaxaAsLink(dataItem, "Category");
                    }

Inside the RenderHierarchicalTaxaAsLink we are passing the Sitefinity Content item that we resolved in the ItemDataBoundEvent and this will allow us to easily get the list of taxa assigned to it:
public string RenderHierarchicalTaxaAsLink(NewsItem newsitem, string taxonomyFieldName)
       {
           var catList = "";
           var itemsToTake = 10;
           //get the Categories assigned to this  news item
           var categories = newsitem.GetValue<TrackedList<Guid>>(taxonomyFieldName).Take(itemsToTake);

Please note the itemsToTake parameter - it controls the maximum number of categories per item that we are going to display. As resolving each category makes a call to the database, we've set that number to 10 intentionally .

Once we have the list of assigned categories what we need to do is load each category, as we currently have only its ID. We can then simply iterate through the list of category IDs, load each category and then using its own Name, the name of the  Taxonomy it belongs to and the name of the single Taxon from that Taxonomy we can construct the filtering URL parameter in a similar fashion: -in-Category/Categories/yourCategoryName . This is the default format our Sitefinity TaxonomyEvaluator is looking for, and it will ensure us the correct filtering behavior. The finishing stop is to combine this with the absolute URL of the page we're currently on and we end up with something like:

if (categories != null && categories.Count() > 0)
            {
                catList = "Categories:</br> ";
                //get the page URL
                var currentUrl = HttpContext.Current.Request.Url.ToString();
                if (!HttpContext.Current.Request.Url.Query.IsNullOrEmpty())
                    currentUrl = currentUrl.Replace(HttpContext.Current.Request.Url.Query, string.Empty);
                if (currentUrl.EndsWith("/"))
                    currentUrl = currentUrl.TrimEnd('/');
                var taxManager = TaxonomyManager.GetManager();
                //load the categories and build their filter URL to construct the clickable links
                foreach (var cat in categories)
                {
                    var t = taxManager.GetTaxon<HierarchicalTaxon>(cat);
                    var url = string.Format("{0}/-in-{1}/{2}/{3}", currentUrl, t.Taxonomy.TaxonName, t.Taxonomy.Name, t.Name);
                    var link = string.Format("<a href='{0}'>{1}</a><br/>", url, t.Name).ToString();
                    catList = catList + link;
                }
            }
            return catList;

With this our job on the custom template is complete - simply build the project and then proceed with specifying the path to the custom template in your widget's advanced settings TemplatePath property, so it will start using the custom template instead of the default one.

For your convenience you can find the complete sample of the custom template attached to this blog post:
CustomTemplates - displaying the categories as clickable links

As an end result you should have the categories you've assigned each item to, displayed as click-able links under each item in the ListView.

A short video demonstrating this functionality can be found here.

As a bottom line I just wanted to point out that although the sample demonstrates achieving this functionality with a News widget, you should be aware of the fact that the approach is pretty much universal, so it can be very easily adapted to any other ContentView based widget if you follow the described steps.

I hope you enjoyed this post, please keep in touch for more useful tips and tricks that can help you customize the product behavior.

1 comment

Leave a comment
  1. Nidhi Nov 18, 2013
    We've often used this little snippet of jquery to achieve this more quickly:

    if (window.location.href.indexOf("myblog") > -1) {
            var tag_url = "/myblog/-in-Tags/Tags/";
            $('.tagList_wrapper ul.sfTagsList li span').each(function (i) {
                var $that = $(this).text();
                var tag_urlname = $that.replace(/\s/g, "-").replace('&', '-');
                $(this).wrap('<a href="' + tag_url + tag_urlname + '" />');
            });
        }

    Leave a comment