Experience Sitecore ! | Welcome Item Reference - a rendering variant field missing out of the box in SXA

Experience Sitecore !

More than 200 articles about the best DXP by Martin Miles

Welcome Item Reference - a rendering variant field missing out of the box in SXA

Note! The code used in this post can be cloned from GitHib repository: SXA.Foundation.Variants
The majority of folks working with SXA are aware of Reference Item variant field - that allows switching a context of rendering variant from a context item (current page or datasource item, if set) to either one or many items referenced by a link-type field of a given context item. It works like a charm, but in some cases one may meet a case where setting datasource is not applicable or you may need your component to show something different apart from provided datasource item - I have already described how to implement that using Query Variant Field. Let's evaluate it:
Pros
  • it comes out of the box, and could be used straight away
  • you may query in more complex way rather just proving an ID
Cons
  • it relies on SXA search index to be in actual state - you need to have it rebuilt
  • writing query is less user friendly then just picking up an item.
So why not to implement a dedicated Item Reference variant field - it definitely pays off, once used often.

This time I picked up built-in Reference variant field as a donor. Instead of PathTrough field I added Item field of Droptree type:



Code-wise, I implemented one property named PassThroughItem. There's also another one to store child fields, nested underneath given reference item field, those will be executed and render in a switched context:
public class VariantItemReference : BaseVariantField
{
    public string PassThroughItem { get; set; }

    public IEnumerable<BaseVariantField> NestedFields { get; set; }
}
Need to reference IDs of template and its single field:
public static class Constants
{
    public static class RenderingVariants
    {
        public static class Templates
        {
            public static ID ItemReference = new ID("...");
        }

        public static class Fields
        {
            public static class ItemReference
            {
                public static ID Item { get; } = new ID("...");
            }
        }
    }
}
Implement a parser:
public class ParseItemReference : ParseVariantFieldProcessor
{
    public override ID SupportedTemplateId => Constants.RenderingVariants.Templates.ItemReference;

    public override void TranslateField(ParseVariantFieldArgs args)
    {
        ParseVariantFieldArgs variantFieldArgs = args;

        var reference = new VariantItemReference();
        reference.ItemName = args.VariantItem.Name;
        reference.PassThroughItem = args.VariantItem[Constants.RenderingVariants.Fields.ItemReference.Item];

        reference.NestedFields = args.VariantItem.Children.Count > 0
            ? ((IVariantFieldParser)ServiceLocator.ServiceProvider.GetService(typeof(IVariantFieldParser))).ParseVariantFields(args.VariantItem, args.VariantRootItem, false)
            : new List<BaseVariantField>();

        variantFieldArgs.TranslatedField = reference;
    }
}
And a renderer:
public class RenderItemReference : RenderVariantFieldProcessor
{
    public override Type SupportedType => typeof(VariantItemReference);

    public override RendererMode RendererMode => RendererMode.Html;
      
    public override void RenderField(RenderVariantFieldArgs args)
    {
        var control = new PlaceHolder();

        var variantItemReference = args.VariantField as VariantItemReference;
        if (!string.IsNullOrWhiteSpace(variantItemReference?.PassThroughItem))
        {
            var newContextItem = Sitecore.Context.Database.GetItem(new ID(variantItemReference.PassThroughItem));
            if (newContextItem != null)
            {
                foreach (BaseVariantField referencedItem in variantItemReference.NestedFields)
                {
                    RenderVariantFieldArgs variantFieldArgs = new RenderVariantFieldArgs
                    {
                        VariantField = referencedItem,
                        Item = newContextItem,
                        HtmlHelper = args.HtmlHelper,
                        IsControlEditable = args.IsControlEditable,
                        IsFromComposite = args.IsFromComposite,
                        RendererMode = args.RendererMode,
                        Model = args.Model
                    };

                    CorePipeline.Run("renderVariantField", variantFieldArgs);
                    if (variantFieldArgs.ResultControl != null)
                    {
                        control.Controls.Add(variantFieldArgs.ResultControl);
                    }
                }
            }
        }

        args.ResultControl = control;
        args.Result = RenderControl(args.ResultControl);
    }
}
Here is the usage:


Don't' forget to add it into Insert Options and hope you'll enjoy it!
Comments are closed