Friday, January 24, 2014

Dynamic Key Placeholders

Dynamic Key Placeholders
This is an overview of Dynamic Key Placeholders and how to create them a video will be created later of this content.  The code for this was posted by Daveleigh at trueclarity.wordpress.com in his article about this subject, note the original implementation of this was based on that found in the article by Nick over at Techniphoria414

Placeholder Limitations
When developing a site in Sitecore there may be a time where you need to have the same layout on a page multiple times.  

The problem with this is that all Placeholder paths must be unique.  Note that I said paths as you can have the same placeholder key on a page multiple time as long as it is nested under different placeholders.  

This can cause a problem when you need to have something like a 2 column layout followed by a 3 column layout and another 2 column layout on the same page.  If you have a layout designed for a news tout, and want multiple on the page.

Usually this is solved by creating multiple sublayouts with different placeholders.  This is not the easiest way to accomplish things, and can actually get quite confusing.  Fortunately there is an easy solution.  That would be DynamicKeyPlaceholders.

What is it?
Dynamic Key Placeholders is an override on the Sitecore Placeholder that increments the key with every instance causing your placeholders to always be unique.  

How It works
A dynamic placeholder looks confusing at first look, but the process is actually quite simple.
  • Find the current placeholder
    • Get the Placeholder Stack
    • Peek at the top of the stack (the last item added)
  • Get current container within that placeholder
    • Get the Renderings from the Context Page (Sitecore.Context.Page.Renderings)
    • Filter them by the current Placeholder Key
    • Check if they have already been added to the page
    • Take the last rendering from the list (the current rendering)
  • How many times does this rendering exist in the current placeholder
    • Filter the Renderings in the current Placeholder by RenderingItem to find all instances of this Rending
    • Take the count of this result
  • Create our Placeholder with Dynamic Key
    • Create a Sitecore Placeholder
    • Set the Key to our Key name with the rendering count appended
    • Add the Placeholder to the page and expand it
How to Implement it
The implementation of dynamic key placeholders is actually more simple than the code behind it. 
  • Add the code to your library (found at the bottom of this post)
  • Register the prefix on your page (Replace Italicized text with your implementation specific values)
    • <add tagPrefix="Prefix Name" namespace="Your Namespace" assembly="Your Assembly Name" />
  • Add your placeholder (Replace Italicized text with your implementation specific values)
    • <Prefix Name:DynamicKeyPlaceholder ID="PlaceholderId" runat="server" Key="KeyName" />
  • Use your placeholder as usual keeping in mind the incrementing key
Dynamic Key Placeholders are not only simple to implement, but prove to be very useful.  They allow you to have very dynamic layouts and offer more flexibility to your clients.

Code:
using System.Collections.Generic;
    using System.Linq;
    using System.Web.UI;
    using Sitecore.Common;
    using Sitecore.Layouts;
    using Sitecore.Web.UI;
    using Sitecore.Web.UI.WebControls;

    /// <summary>
    ///
    /// </summary>
    public class DynamicKeyPlaceholder : WebControlIExpandable
    {
        protected string _key = Placeholder.DefaultPlaceholderKey;
        protected string _dynamicKey = null;
        protected Placeholder _placeholder;

        /// <summary>
        ///
        /// </summary>
        public string Key
        {
            get { return _key; }
            set { _key = value.ToLower(); }
        }

        protected string DynamicKey
        {
            get
            {
                if (_dynamicKey != null)
                {
                    return _dynamicKey;
                }
                _dynamicKey = _key;

                // Find the last placeholder processed.
                Stack<Placeholder> stack = Switcher<Placeholder,
                    PlaceholderSwitcher>.GetStack(false);
                Placeholder current = stack.Peek();

                // Group of containers which sit in the current placeholder (i.e. they have the same placeholder id).
                var renderings = Sitecore.Context.Page.Renderings.Where(rendering => (rendering.Placeholder == current.ContextKey || rendering.Placeholder == current.Key) && rendering.AddedToPage).ToArray();

                // Current container
                var thisRendering = renderings.Last();

                // get all repeating containers in the current placeholder
                renderings = renderings.Where(i => i.RenderingItem != null && i.RenderingItem.ID == thisRendering.RenderingItem.ID).ToArray();

                // Count represents how many of the same container have already been added to the page
                if (renderings.Any())
                {
                    _dynamicKey = _key + renderings.Count();
                }
                return _dynamicKey;
            }
        }

        protected override void CreateChildControls()
        {
            _placeholder = new Placeholder {Key = DynamicKey};
            Controls.Add(_placeholder);
            _placeholder.Expand();
        }

        protected override void DoRender(HtmlTextWriter output)
        {
            base.RenderChildren(output);
        }

        #region IExpandable Members

        /// <summary>
        ///
        /// </summary>
        public void Expand()
        {
            EnsureChildControls();
        }

        #endregion
    }

No comments:

Post a Comment