3

Is there a way to find out if a dynamic placeholder has renderings in it? I'm currently using Fortis Collection's implementation of dynamic placeholders which was included in the project through nuget. I've only done this with normal placeholders and it involved using the placeholder's name similar to this: https://stackoverflow.com/a/24362438/2597149. This won't work since I don't know the exact string of the placeholder to use.

1 Answer 1

6

Updated

OK - so this is a lot more complex than I thought it might be. Basically, because of the way that Sitecore handles renderings and placeholders, there is no way of getting all the placeholder keys for a page. You can only list placeholder keys where rendering has been added to it.

Finding Rendering inside Dynamic Placeholders

You can easily find renderings that have been added to a dynamic placeholder, without knowing the full key name including the Guid:

Sitecore.Context.Page.Renderings
    .Where(r => r.Placeholder.StartsWith("PromoItems_", StringComparison.OrdinalIgnoreCase))

This code will get you the renderings that have been added to any of the PromoItems dynamic placeholders. This works because the dynamic placeholder code uses this format ({placeholderKey}_{renderingId}), to create the full dynamic placeholder key.

Getting a PlaceholderKey that has not been used

To get hold of a placeholder key that has not had any components added to it, you have to grab it when the page is being composed. When you add @Html.Sitecore().DynamicPlaceholder(), once it has worked out the key - it still just runs through the mvc.renderPlaceholder pipeline. In this pipeline, it calls a GetRenderings method that... wait for it... gets all the renderings for that placeholder key:

protected virtual IEnumerable<Rendering> GetRenderings(string placeholderName, RenderPlaceholderArgs args)
{
    string placeholderPath = PlaceholderContext.Current.ValueOrDefault(context => context.PlaceholderPath).OrEmpty();
    Guid deviceId = this.GetPageDeviceId(args);
    return args.PageContext.PageDefinition.Renderings.Where<Rendering>(r =>
    {
        if (!(r.DeviceId == deviceId))
            return false;
        if (!r.Placeholder.EqualsText(placeholderName))
            return r.Placeholder.EqualsText(placeholderPath);
        return true;
    });
}

Depending on what you wanted to do with that empty placeholder, you could override the PerformRendering processor and check if a rendering had components or not.

Here is an example that stores a list of keys in Sitecore.Context.Items, which you could then use somewhere else in the code:

public class PerformRendering: Sitecore.Mvc.Pipelines.Response.RenderPlaceholder.PerformRendering
{
    protected override void Render(string placeholderName, TextWriter writer, RenderPlaceholderArgs args)
    {
        var renderingsForPlaceholder = this.GetRenderings(placeholderName, args).ToList();
        if (!renderingsForPlaceholder.Any())
        {
            // Do something here? Maybe store it in Sitecore.Context.Items to be used later?
            var unusedPlaceholders = Sitecore.Context.Items["unusedPlaceholderKeys"] as List<string> ?? new List<string>();
            unusedPlaceholders.Add(placeholderName);
            Sitecore.Context.Items["unusedPlaceholderKeys"] = unusedPlaceholders;
        }

        foreach (Rendering rendering in renderingsForPlaceholder)
        {
            if (rendering != null)
            {
                using (this.CreateCyclePreventer(placeholderName, rendering))
                    this.ProcessRenderRendering(rendering, writer);
            }
        }
    }
}

Hopefully, that helps solve your problem!

2
  • I am using dynamic placeholders because I want to reuse a placeholder name multiple times on a page. Won't the snippet you've included end up getting a count of all renderings in each dynamic placeholder with the name PromoItems?
    – Teeknow
    Commented Oct 9, 2017 at 22:49
  • 1
    @TeeKnow Sorry took a bit longer than I thought. But the solution above should help.
    – Richard Seal
    Commented Oct 10, 2017 at 21:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.