Custom SXA Component with rendering variants - Feature Block List Development in 24 steps
Although Clone rendering in SXA is a good feature, I feel it is a good option for simple controls but not complex ones like lists for obvious reasons like clone is intended to clone existing functionality as-is and can't expect it to be perfect for your custom requirement. I'll probably update this blog later as to where clone rendering causes issues in case if you attempt to create a Feature Block List from File List and look at steps to make the cloned rendering work.
For now, this blog post is a pictorial step-by-step walk-through of creating a Feature Block List in Sitecore 10.3 SXA using Sitecore documentation + File List component dotpeek code.
Feature Block List or simply, Feature List usually looks like this and understandably this is a very important component, present in most home pages:
1. Create following templates:
1.1 Under Datasource folder
- Feature Block copied from /sitecore/templates/Feature/Experience Accelerator/Media/Datasource/File
Create following fields:
- Feature Block List copied from /sitecore/templates/Feature/Experience Accelerator/Media/Datasource/File List
Inheritance in action:
- Feature Block List Folder copied from /sitecore/templates/Feature/Experience Accelerator/Media/Datasource/File List Folder
In both of the above cases, ensure proper insert option is set for respective item standard values since if copied from File List or File List Folder, they will point to file-related items instead of correct Feature Block or Feature Block List:
For example, Feature Block List item Standard Values assigned Feature Block item:
1.2 Under Rendering Parameters, in order to use existing inheritance, create Feature Block List Parameters by copying and renaming /sitecore/templates/Feature/Experience Accelerator/Media/Rendering Parameters/FileListParametersTemplate
2. Under Templates > Branches, create variants
3. Under Renderings, create controller rendering:
4. Ensure Datasource Location and Datasource Template point to correct/relevant path if copying from an existing rendering:
6. Create featurelist under Placeholder Settings (probably not so important but following existing File List component flow):
7. Under tenant > site > Presentation > Available Renderings, create an Available Rendering named Custom Renderings and add Feature Block List rendering.
Ensure Originator is set to branch template variant.
8. Similarly, under /sitecore/content/<tenant>/<site>/Presentation/Rendering Variants, add Variants named Feature Block List
Then, use the branch template created in step 2 to create the variant tree:
9. Variant list created using branch template under /sitecore/content/<tenant>/<site>/Presentation/Rendering Variants:
12. Under Repositories, create IFeatureListRepository and add the following interface code to follow SOLID principle in our development methodology (thanks dotpeek):
////////////
using Sitecore.XA.Foundation.IoC;
using Sitecore.XA.Foundation.Mvc.Repositories.Base;
using Sitecore.XA.Foundation.RenderingVariants.Lists.Pagination;
namespace CustomSXA.Feature.CustomRenderings.Repositories
{
public interface IFeatureListRepository :
IModelRepository,
IControllerRepository,
IAbstractRepository<IRenderingModelBase>
{
IRenderingModelBase GetModel(IListPagination paginationConfiguration);
}
}
//////////
13. Next, Create the FeatureListRepository that fills the model based on the selected datasource and this encapsulated data will be passed onto the controller (thanks dotpeek):
//////////////////////////
using Sitecore.Data.Items;
using Sitecore.XA.Foundation.IoC;
using Sitecore.XA.Foundation.Mvc.Repositories.Base;
using Sitecore.XA.Foundation.RenderingVariants.Lists.Pagination;
using Sitecore.XA.Foundation.RenderingVariants.Models;
using Sitecore.XA.Foundation.RenderingVariants.Repositories;
using System.Collections.Generic;
using System.Linq;
namespace CustomSXA.Feature.CustomRenderings.Repositories
{
public class FeatureListRepository :
ListRepository,
IFeatureListRepository,
IModelRepository,
IControllerRepository,
IAbstractRepository<IRenderingModelBase>
{
public override IRenderingModelBase GetModel()
{
VariantListsRenderingModel variantListsRenderingModel = new VariantListsRenderingModel();
this.FillBaseProperties((object)variantListsRenderingModel);
variantListsRenderingModel.Items = this.GetItems();
return (IRenderingModelBase)variantListsRenderingModel;
}
public IRenderingModelBase GetModel(IListPagination paginationConfiguration)
{
VariantListsRenderingModel variantListsRenderingModel = new VariantListsRenderingModel();
this.FillBaseProperties((object)variantListsRenderingModel);
variantListsRenderingModel.Items = (IEnumerable<Item>)this.GetItems().Skip<Item>(paginationConfiguration.Skip).Take<Item>(paginationConfiguration.PageSize).ToList<Item>();
return (IRenderingModelBase)variantListsRenderingModel;
}
}
}
/////////////////////////
14.a In the controller, add the following code that gets the model from assigned datasource and uses the StandardController base class to invoke the underlying Index action method (thanks dotpeek):
//////////
using CustomSXA.Feature.CustomRenderings.Repositories;
using Sitecore.XA.Foundation.RenderingVariants.Controllers.Base;
namespace CustomSXA.Feature.CustomRenderings.Controllers
{
public class FeatureListController : PaginableController
{
protected IFeatureListRepository FeatureListRepository { get; }
public FeatureListController(IFeatureListRepository repository) => this.FeatureListRepository = repository;
protected override object GetModel() => (object)this.FeatureListRepository.GetModel(this.PaginationConfiguration);
}
}
////////
16. Patch file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<services>
<configurator type="CustomSXA.Feature.CustomRenderings.App_Start.RegisterDependencies, CustomSXA.Feature.CustomRenderings" />
</services>
</sitecore>
</configuration>
17. Create a publish profile and deploy this application to the web root.
18. Back in Sitecore, glue the .net controller to the Sitecore controller rendering:
19. Next, create a data source in Sitecore for the Feature Block:
20. Now, in content editor, open the <tenant> /<site>/ home page in XPE and in the SXA toolbox, should see a module named Custom Renderings and within that a control named Feature Block List since Available renderings is configured in step 7:
21. Drag and drop the new rendering to main placeholder and the content created in step 19 must be visible to pick:
22. The component should be content-editable and visible now with the option to select different variants:
23. Select a variant, save and do Sitecore Publish to view the desired end-result in the web page:
YSOD:
Server Error in '/' Application.
Could not load file or assembly 'System.Text.Encodings.Web' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.IO.FileLoadException: Could not load file or assembly 'System.Text.Encodings.Web' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
Source Error:
Solution:
Set Copy Local to False for this dll reference:
at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
at Sitecore.Mvc.Controllers.ControllerRunner.GetController()
at Sitecore.Mvc.Controllers.ControllerRunner.Execute(TextWriter writer)
at Sitecore.Mvc.Pipelines.Response.RenderRendering.ExecuteRenderer.Render(Renderer renderer, TextWriter writer, RenderRenderingArgs args)
Inner Exception: The controller for path '/' was not found or does not implement IController.
at System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType)
at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
Comments
Post a Comment