Sitecore Sublayout Parameters and Datasources

April 27, 2011
Tags: Sitecore

Some of the most useful features in Sitecore are also some of the least well known. The longer you work with anything, the more you begin to understand it. With something as complex as Sitecore you really have to spend a lot of time learning what it can do before you start to really see how well it's suited to solving a lot of different problems.

Sitecore's sublayouts, for example, contain a wealth of technology that is not really documented, but it's the bedrock of an effective solution. The sublayout definitions in a presentation definition are where you determine where it appears on a page. The cache settings will really help you scale up in terms of traffic. Then there are the datasource and parameter fields. Now at first I largely ignored them because I'm often in a race to solve a dozen problems and I'm just limiting the scope of what I need to research but eventually you start to question what all these other features can do and surprisingly they can do quite a bit.

So enough gum flapping. Let's see what they do and why you'd want to use them. Depending on which version of Sitecore you're using the presentation details window may differ but you'll see something similar to what's in the image below.

 sublayout properties dialog window

The datasource is a LinkField and will be used to store the Sitecore ID of an item in your tree. Okay so if you're relatively new you may say "I'm used to expecting the datasource for a sublayout to be the context item, that's where I store all the information and that's how I like it." Well yes, often times the context item will contain a lot of the information that you'll want to display on a page but not necessarily all of it and of course you might want to setup a way to share data across a large number of pages efficiently. Big shout out to the development engineers for thinking so far ahead and providing this feature. Let's take one of I'm sure many use cases for this kind of feature. Let's say for instance you want to have a contact information list on the sidebar of a page and that information should be global. Now along with all good inheritance schemes you'll start the setup at a template's standard values level. Here you'll assign the sublayout and set the datasource to the global contact information. This will ensure that 1). you won't have to implement a library method to traverse the tree and find the global contact information on every page load and 2). that if and when you or you're client decides that some small subset of pages should have a different source for the contact information you can go to those pages and override the datasource value. Now let it sink in for a while and I'm sure you'll end up finding at least a dozen other uses for this. Really, really powerful feature here. Okay now you're all fired up and you set this up and switch over to Visual Studio and you open the code behind and realize, "How do I access that datasource?" Excellent question, and thanks to the contributions of none other than Mark Ursino here's what you'll need to do just that:

using Sitecore.Data.Items;using Sitecore.Web.UI.WebControls;private Item _dataSource = null;	/// /// Access the Item assigned in the DataSource field on a sublayout/// public Item DataSource {	get {		if (_dataSource == null)			if(Parent is Sublayout)				_dataSource = Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);		return _dataSource;	}}

For reference the "Parent" object is a reference to the control.Parent of a System.Web.UI.UserControl class and the Sublayout object is a reference to a Sitecore.Web.UI.WebControls class. What you'll notice is that we're accessing the DataSource property on the sublayout and retrieving a

Now on to the parameters. What you'll find here is a list of key/value pairs that you can seemingly add at infinitum. I haven't tested it but you should be able to add enough pairs to satisfy you, unless of course you're a jerk and you just have to break it to find out. In that case nothing I say will matter so forget you. For the rest of you you're probably asking why do you talk to yourself so much in your articles. Because. Just because. Anyway you're likely looking for a good use case for this kind of feature to really understand the implications of such a feature. So let's say you've got form on this sublayout and you want to popup a message indicating a privacy policy to the user before they submit information. Ok that's useful but sometimes you need to, legally, warn them every time they visit the page and other times you may only need to warn them once. You don't want to go duplicating all the functionality in the sublayout to another sublayout so that one sets a cookie and one doesn't. You'd rather just set a default to true/false parameter and then override the individual pages that differ. You'll get a lot more mileage from that single sublayout without all the fuss. Now you're again all ready to get the values and suddenly realize you have no idea how to access them. Well this time I've got you covered and since I love extension methods, that's how I've prepared the code for you. Boom.

using System.Collections.Specialized;using Sitecore.Web.UI.WebControls;public static class SublayoutExtensions{		public static NameValueCollection ParameterList(this Sublayout s) {				return Sitecore.Web.WebUtil.ParseUrlParameters(s.Parameters);		}} public static class NameValueCollectionExtensions {	public static bool HasKey(this NameValueCollection QString, string Key) {		foreach (string key in QString.Keys) {    			if (key.Equals(Key)) {     				return true;    			}   		}	return false;  	}}NameValueCollection nvc = ((Sublayout)Parent).ParameterList();if (nvc.HasKey("TestKey")) {	Response.Write(nvc["TestKey"]);}

Again like the datasource field you're going to be accessing the UserControl parent Sublayout object to get the parameters which will give you the values in a querystring format. Sitecore also provides a nifty utility class to convert that querystring into a NameValueCollection for you and I've provided an extension method for the NameValueCollection called "HasKey" because for some unforseen reason it doesn't exist.

So hopefully if you don't know about these features you'll spend a lot less time than I did figuring them out and if you have some better use cases feel free to share them in the comments.