Sitecore’s fundamental architecture separates various concerns of the CMS into different pieces. This separation makes the CMS very extensible, customizable, and easy to work with. Sitecore’s presentation layer is broken down into layouts and renderings (XSL renderings, sublayouts, WebControls). Specifically within sublayouts is a feature to dynamically assign a data point to the presentational component. This article will cover the use of using the sublayout DataSource field, how to read the DataSource, and why its useful.
I’ve actually had this article written for some time, but after still seeing questions asked about the topic, I figure its time to publish. I first learned about the concept during my Sitecore OMS training where Multi-Variant tests require dynamic data sources to sublayouts. Each data source in a MV Test can be shown to a user as a possible variation in the test and metrics are collected on that specific data source’s use.
Data and Presentation Abstraction
The purpose of the DataSource field on a sublayout is to abstract away from the implementation (ASCX) the data to pull into the component. A sublayout is a presentational component. It shouldn’t specifically know about the exact data it needs to use (only the fields), unless it’s built for a very specific purpose (header, footer, etc.).
Say we have a sublayout called Promo Box that reads in the following fields from some Sitecore item:
- Headline
- Promo Image
- Teaser Text
- Promo Link
The ASCX control can be coded to read in these fields and use them on the front-end display, but what if the site should have 0-n of these Promo Boxes? This is where the abstraction between the presentation and the data comes into place. The idea here is that we define the presentation in the ASCX but assign a specific Sitecore item as the DataSource for each specific Promo Box sublayout binding. Let’s take a look at some examples in the screenshots below.
Here’s a data template called Promo Box Data, with the same four fields I mentioned above. This is the template that we will create various items with for different data sources. Remember, this is just the data definition:
Below is a screenshot that shows two instances of these data items in a global folder so they can be used on any pages. Each of these uses this new template for various promo details. The full screenshot doesn’t show it, but believe me that it has all four fields discussed above.
Now that we have data items to represent the data aspect, let’s assign the presentational component to a page. Below is a screenshot of the Promo Box sublayout being added to a page’s presentation details. Notice I checked the Open Properties checkbox. This will allow me to immediately define a specific DataSource after clicking Select:
Now you can specify the specific data to bind to this component. Click the Insert Link on the Data Source field and point it to one of the data instances that I created earlier. This step couples the presentation to the specific data for this specific sublayout instance:
Now you can continue to do this with more sublayouts. You can add another Promo Box component to the page, but assign a different data source. Unfortunately the presentation details view doesn’t show the data source unless you click Edit, so it can be a bit tricky to know which sublayout is pointing to which data item:
Access the DataSource via the BaseSublayout
Now let’s look into how we can code to read from this Data Source field. To access the DataSource item from a ASCX control, you just need to see if the control’s parent is a “Sublayout” and if so, cast it to one and access the DataSource property from that. This can be automated by adding in the following BaseSublayout.cs
class which wraps over a built-in UserControl
. You can just make any ASCX control inherit from this class to expose the extra DataSource property:
[csharp]
using Sitecore.Data.Items;
using Sitecore.Web.UI.WebControls;
public class BaseSublayout : System.Web.UI.UserControl {
private Item _dataSource = null;
public Item DataSource {
get {
if (_dataSource == null)
if(Parent is Sublayout)
_dataSource = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);
return _dataSource;
}
}
public BaseSublayout() : base() { }
}
[/csharp]
Now here’s an example of using this in a ASCX control. For this example, the template for a valid DataSource item for a Promo Box sublayout would be “Promo Box Data” as shown above. Here we need to validate against the DataSource item to make sure its using the right template. If not, it would be nice to either hide the whole component or possibly log it too.
[csharp]
<asp:PlaceHolder ID="phPromoBox" Visible="false" runat="server"><br />
<sc:Text ID="sctHeadline" Field="Headline" runat="server" /><br />
<sc:Image ID="sciPromoImage" Field="Promo Image" runat="server" /><br />
<sc:Text ID="sctTeaserText" Field="Teaser Text" runat="server" /><br />
<sc:Link ID="sclPromoLink" Field="Promo Link" runat="server"></sc:Link>
</asp:PlaceHolder>
[/csharp]
[csharp]
public partial class PromoBox : BaseSublayout {
if(DataSource != null && DataSource.TemplateName == "Promo Box Data") {
sctHeadline.DataSource =
sciPromoImage.DataSource =
sctTeaserText.DataSource =
sclPromoLink.DataSource = DataSource.ID.ToString();
phPromoBox.Visible = true;
} else {
// either the DataSource was not set OR it was set to an item of
// the wrong template, so it doesn’t have the required fields
}
}
[/csharp]
Following this pattern, architects and developers can easily create re-usable components that have the same presentation but different data. I’ll go into more details in a future article, but this also make it very easy to cache this sublayout and “vary by data” since each sublayout binding will point to various data sources.
Additional Reading
I have not used it myself but there’s a shared source module that makes it easy to access sublayout parameters defined in Sitecore as well: Sublayout Parameter Helper.
We should always remember one thing: when we assign a DataSource for some rendering, the rendering actually contains the path (Sitecore tree path) to the DataSource item. So, in the example, if we move the data source items to another location we won’t get the control to work properly.
Unfortunately, for some reason, it stores just the path, not the item ID.
Excellent point Ivan.
The reason for that is the fact that the DataSource field is an “Internal Link” which stores references by the path, which is the biggest issue with Internal Links and why you should never use them on your own templates.
Thanks for the article its been a great help implementing several components within our website.
Thank you for this post! I could not figure out how to get the field data out of that Data Source from within the control, and this worked perfectly.
any idea how to do this with mvc view renderings/controller renderings/item renderings?
Hi and Thank you for this Post.
Is there any method to use an external data source ?!
In this example all Promo bloc data comes from sitecore items, but how is it difficult if my Promo data comes from outside (such as webservice, or another sitecore website)
Hi Mark,
I’m trying to use this, doing pretty much exactly what you’re doing here, and am running into that the Parent is not castable to a Sublayout. It’s definitely a sublayout in Sitecore, and inherits from System.Web.UI.UserControl just like all our other sublayouts. Whenever I try to cast the Parent as a Sublayout, it comes back null. I can’t find that we’ve done anything out of the ordinary here, and it looks like it should be working — any ideas why this might be happening, and what I could do to address it?
Thanks in advance if you can help.
-C
Caroline –
How are you binding that sublayout to the page? Dynamically in Sitecore via Layout Details or statically in C# code?
Kiran – I think its
this.Rendering.DataSource
I am doing pretty much same but getting either blank or null sitecore 6.5.
Sitecore.Context in below snippet always returning the id of sitecore page in which I have added presentation details instead of rendering id.
Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource)
I have added 2 renderings to the page item in sitecore. In code behind of one of my rendering I want to fetch data source assigned to it.