Creating a custom SXA rendering with variants

In this blog post we’ll step through the process of creating a custom SXA rendering with variants.  For this example, we’ll create a rendering that is used to display information about cars.  By using a rendering with variants, we can add a Car rendering to our page, and depending on which variation we choose, we can display it with a different appearance and different fields.  We’ll create a Car rendering with 3 variations:

  • Summary
  • Specifications
  • Full Details

Template

The first thing we need to do is create the template.  Even though some of the variations only display some of the fields, the template will have all of the fields for a car, and the variations will use only the fields they need.

Template

This template was created in /sitecore/templates/Feature/Cars/Car.

Rendering

The next step is to create the rendering.  Ours was created at /sitecore/layout/Renderings/Feature/Cars/Car.  The rendering should be a Controller Rendering.  Set the Controller (this one has been set to “Car”), and set the Controller Action to “Index”.  Set the Datasource Template to be the template we’ve just created (in this case, /sitecore/templates/Feature/Cars/Car), and the Datasource Location to “query:$site/*[@@name=’Data’]/|*[@@templatename=’Car’]”.  It’s important to set “Editable” to true so that the rendering will be available in the Toolbox.

Rendering

To make the rendering appear in the toolbox, we need to add it to Available Renderings.  The Available Renderings folder is  found under the Presentation folder of your SXA site.  First add an Available Renderings item under the Available Renderings folder.  In this case, I’ve added one called Cars.  Once you’ve added the Available Renderings item, click “Edit” on the Renderings field, and add your new rendering (“Car”) to the list of renderings.

AvailableRenderings

It doesn’t really matter what you call the Available Renderings item, or which Available Renderings item our rendering is added to, because the Available Renderings item is simply for filtering/organising the rendering in the content tree.  It doesn’t actually determine where it appears in the Toolbox.  The folder structure of where the rendering is located determines this.  For example, because this rendering is at /sitecore/layout/Renderings/Feature/Cars/Car, it will appear in the Toolbox under a new category of “Cars”.

Toolbox

Rendering Variants

This is where we setup the 3 variations of the rendering.  To start off, create a new Variants item called “Car” under the Presentation/Rendering Variants folder of your SXA site. Under that item, create 3 Variant Definition items for each of the variants we need.

When the variants have been added, they can be selected from the Variant dropdown list in the Experience Editor:

ListVariants

Under each of the Variant Definitions, we need to insert the fields to be displayed.  The desired layout of these fields will determine how we add the fields.  The fields can be grouped into sections, and the order and hierarchy of the fields directly matches the order and hierarchy of the HTML elements that get rendered.  This, coupled with the “Css Class” field allows you to have full control over the layout and appearance of the variant.   The beauty of this is that once this initial setup has been done, you can add as many variants to this rendering as you like without having to write any more code at all.

When adding the fields, it is important that the value of the “Field name”  matches the name of the field in the template.

As an example, the Summary variant has been created using this following structure:

SummaryVariant

The Css Class for the Image field has been set to “col-xs-3”, and the Css Class for the Car Details section has been set to “col-xs-9”.  The Tags for all of these items are using the default of “div”.  This configuration translates to the following HTML:

<div class="component car">
   <div class="component-content">
      <div class="col-xs-3 field-image">
         <img style="margin:0;" src="/-/media/458B8369BE6D40489797D75DDA8BB79D.jpg?h=114&la=en&w=200&hash=641FD08747F050B6AF1779E77E5BF2C24AB2CEC0" alt="" width="200" height="114" />
      </div>
      <div class="col-xs-9">
         <div class="field-make">Holden</div>
         <div class="field-model">Commodore</div>
         <div class="field-year">2007</div>
      </div>
   </div>
</div>

And it looks like this:

SummaryVariantRendered

As an example, we can have a completely different look for the same rendering by selecting the Full Details variant, which has been setup like this:

FullDetailsVariant

And it ends up looking like this:

FullDetailsVariantRendered

There’s a great article that covers this in more detail at http://www.markvanaalst.com/sitecore-experience-accelerator/the-power-of-the-variants/

Code

This section covers the code that needs to be created in your solution.

First add a new Feature module to your solution, then add the following items:

IRepository

using Sitecore.XA.Foundation.RenderingVariants.Repositories;

namespace YourBusiness.Feature.Cars.Repositories
{
   public interface ICarRepository : IVariantsRepository
   {
   }
}

Repository

using YourBusiness.Feature.Cars.Modes;
using Sitecore.XA.Foundation.Mvc.Repositories.Base;
using Sitecore.XA.Foundation.RenderingVariants.Repositories;

namespace YourBusiness.Feature.Cars.Repositories
{
 public class CarRepository : VariantsRepository, ICarRepository
  {
     public override IRenderingModelBase GetModel()
     {
         CarModel model = new CarModel ();
         FillBaseProperties(model);
         return model;
     }
  }
}

Model

No need to add our template fields in this instance

using Sitecore.XA.Foundation.Variants.Abstractions.Models;

namespace YourBusiness.Feature.Cars.Models
{
   public class CarModel : VariantsRenderingModel
   {
   }
}

Controller

Keep in mind that the controller must inherit from Sitecore.XA.Foundation.Mvc.Controllers.StandardController.  The Standard controller will handle the routing with default action result “Index”, so there’s no need to add our own, although we can override “Index” if we need to.

using YourBusiness.Feature.Cars.Repositories;
using Sitecore.XA.Foundation.Mvc.Controllers;
using Sitecore.XA.Foundation.RenderingVarients.Repositories;

namespace YourBusiness.Feature.Cars.Controllers
{
   public class CarController: StandardController
   {
       protected ICarRepository CarRespository
       {   get; set;   }

       protected IVariantsRepository VariantsRespository
       {   get;  set;  }

       public CarController(ICarRepository, carRepository, IVariantsRepository variantsRepository)
       {
           this.CarRespository = carRepository;
           this.VariantsRespository = variantsRepository;
       }

       protected object GetVariantsModel()
       {
           return VariantsRespository.GetModel();
       }

       protected override object GetModel()
       {
          return CarRepository.GetModel();
       }
   }
}

View

It is important that all SXA components should be wrapped in “component” and “component-content” divs. “Model.Attributes” adds styles from the rendering parameters.

@model YourBusiness.Feature.Cars.Models.CarModel

@if (Model.DataSourceItem != null || Html.Sxa().IsEdit)
{
<div>
   <div class="component-content">
      @if (Model.DataSourceItem == null) 
      { 
         @Model.MessageIsEmpty 
      } 
      else 
      { 
         foreach (VariantFieldBase variantField in Model.VariantFields) 
         { 
            @Html.RenderingVariants().RenderVariant(variantField, Model.Item, Model.RenderingWebEditingParams) 
         } 
      }
   </div>
</div>
}

Config

<?xml version="1.0" encoding="utf-8"?>

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
    <sitecore>
        <services>
            <configurator type="YourBusiness.Feature.Cars.Pipelines.RegisterCarServices, YourBusiness.Feature.Cars" />
        </services>
    </sitecore>
</configuration>

]

Pipeline

Here we register the dependencies.

using Microsoft.Extensions.DependencyInjection;
using YourBusiness.Feature.Cars.Repositories;
using Sitecore.DependencyInjection;
using Sitecore.XA.Foundation.RenderingVariants.Repositories;

namespace YourBusiness.Feature.Cars.Pipelines
{
   public class RegisterCarServices : IServicesConfigurator
   {
      public void Configure(IServiceCollection serviceCollection)
      {
         serviceCollection.AddTransient<ICarRepository, CarRepository>();
         serviceCollection.AddTransient<IVariantRepository, VariantRepository>();
      }
   }
}

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: