In this blog post, I will explain how to create a Custom Rendering Contents Resolver to be used for a JSS component.
To know more about Rendering Contents Resolvers, you can refer to my previous article here. Here, I created a CardList Component with a built-in Rendering Contents Resolver named Datasource Item Children Resolver.
If I need to utilize both the children items and the fields in the datasource item, we do not have a way to do so. This will either need a GraphQL query or a Custom Renderings Contents Resolver. I will be creating a Custom Renderings Contents Resolver in this example.
Open your solution in Visual Studio.
As per your requirement, create a Helix project or use an existing project.
Create a class extending the class Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver.
Override the ResolveContents method as per your requirement. In my example, I need the datasource item, and the children items. Below will be the implementation.
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json.Linq;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.LayoutService.Configuration;
using Sitecore.LayoutService.ItemRendering.ContentsResolvers;
using Sitecore.Mvc.Presentation;
namespace JSSProject.Resolvers
{
public class DatasourceWithChildrenResolver : RenderingContentsResolver
{
public override object ResolveContents(Rendering rendering, IRenderingConfiguration renderingConfig)
{
Assert.ArgumentNotNull(rendering, nameof(rendering));
Assert.ArgumentNotNull(renderingConfig, nameof(renderingConfig));
Item datasourceItem = this.GetContextItem(rendering, renderingConfig);
if (datasourceItem == null)
return null;
JObject jobject = ProcessItem(datasourceItem, rendering, renderingConfig);
IEnumerable<Item> items = GetItems(datasourceItem);
List<Item> itemList = items != null ? items.ToList() : null;
if (itemList == null || itemList.Count == 0)
return jobject;
jobject["items"] = ProcessItems(itemList, rendering, renderingConfig);
return jobject;
}
}
}
Build and deploy your solution.
Login to Sitecore and go to the Path: /sitecore/system/Modules/Layout Service/Rendering Contents Resolvers
Insert an item with the template: Rendering Contents Resolver named Datasource With Children Items Resolver.
Add the field values as needed:
Go to your rendering item, and change the value for the field Rendering Contents Resolver to the Custom Rendering Contents Resolver we created.
Now, go to the datasource template and add the fields as required. I will be adding a field named cardListHeading to my CardList template.
Go to your datasource item, and fill the values for the fields created.
Save and publish to clear the cache.
Now, go to the GraphQL Playground and perform a layout query for your page. It should have the fields added in the response. Query:
# Write your query or mutation here
query {
layout(site: "JSSProject", routePath: "/demo", language: "en") {
item {
rendered
}
}
}
Response:
{
"data": {
"layout": {
"item": {
"rendered": {
"sitecore": {
"context": {
"pageEditing": false,
"site": {
"name": "jssproject"
},
"pageState": "normal",
"language": "en",
"itemPath": "/demo"
},
"route": {
"name": "demo",
"displayName": "demo",
"fields": {
"pageTitle": {
"value": ""
}
},
"databaseName": "web",
"deviceId": "fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3",
"itemId": "1a4a3d34-df6a-463f-8b72-58cc56ecc0d4",
"itemLanguage": "en",
"itemVersion": 1,
"layoutId": "aec6b942-174e-581c-a1a0-50aa51432a66",
"templateId": "74e5c244-4fb5-5ae9-bb19-0899d55bf312",
"templateName": "App Route",
"placeholders": {
"jss-main": [
{
"uid": "a52a4929-2ac1-4e8a-9a16-1372465c3ac0",
"componentName": "CardListComponent",
"dataSource": "{6539F816-642F-4B48-B5F7-658ABFE4B676}",
"params": {},
"fields": {
"cardListHeading": {
"value": "Card List Heading"
},
"items": [
{
"id": "8a43ce24-7ba2-4953-8392-8517b0ad5f32",
"url": "/demo/Page-Components/CardListComponent/Card-1",
"name": "Card 1",
"displayName": "Card 1",
"fields": {
"title": {
"value": "GraphQL"
},
"description": {
"value": "GraphQL"
},
"link": {
"value": {
"href": "/en/graphql",
"text": "",
"anchor": "",
"linktype": "internal",
"class": "",
"title": "",
"target": "",
"querystring": "",
"id": "{E507735E-CF6D-57C1-8B02-704027972952}"
}
},
"image": {
"value": {
"src": "https://cm.jssproject.localhost/-/media/System/Email/Placeholders/image300x200.jpg?h=200&iar=0&w=300&hash=2D743D7A0F958598889BE6E80062B606",
"alt": "Placeholder image",
"width": "300",
"height": "200"
}
}
}
},
{
"id": "05917a7f-0b00-4234-91d7-1faf45d5d7c0",
"url": "/demo/Page-Components/CardListComponent/Card-2",
"name": "Card 2",
"displayName": "Card 2",
"fields": {
"title": {
"value": "Styleguide"
},
"description": {
"value": "Styleguide"
},
"link": {
"value": {
"href": "/en/styleguide",
"text": "",
"anchor": "",
"linktype": "internal",
"class": "",
"title": "",
"target": "",
"querystring": "",
"id": "{5F92EEFB-A658-56BA-98B3-0C0B1E6420E2}"
}
},
"image": {
"value": {
"src": "https://cm.jssproject.localhost/-/media/System/Email/Placeholders/image300x200.jpg?h=200&iar=0&w=300&hash=2D743D7A0F958598889BE6E80062B606",
"alt": "Placeholder image",
"width": "300",
"height": "200"
}
}
}
}
]
}
}
]
}
}
}
}
}
}
}
}
Go to the component definition in your Next.js solution and the change the code to as below.
import {
Text,
Field,
withDatasourceCheck,
LinkField,
ImageField,
Link,
Image,
} from '@sitecore-jss/sitecore-jss-nextjs';
import { ComponentProps } from 'lib/component-props';
type CardProps = {
id: string;
fields: {
title: Field<string>;
description: Field<string>;
link: LinkField;
image: ImageField;
};
};
type CardListComponentProps = ComponentProps & {
fields: {
cardListHeading: Field<string>;
items: CardProps[];
};
};
const CardListComponent = ({ fields }: CardListComponentProps): JSX.Element => (
<div className="container">
<Text field={fields.cardListHeading} tag="h2" className='h2' />
<div className="flex flex-row">{fields?.items?.map((card) => card && <Card {...card} />)}</div>
</div>
);
const Card = ({ fields, id }: CardProps): JSX.Element => (
<div className="basis-1/2" key={id}>
<Text field={fields.title} tag="h3" className='h3'/>
<Text field={fields.description} tag="p" />
<Link field={fields.link} className="link-field">
<Image field={fields.image} />
</Link>
</div>
);
export default withDatasourceCheck()<CardListComponentProps>(CardListComponent);
Save and reload your page.
Happy Sitecoring!