All Articles

Sitecore JSS with Next.js - Custom Rendering Contents Resolver

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.

Creating a Custom Renderings Contents Resolver

  1. Open your solution in Visual Studio.

  2. As per your requirement, create a Helix project or use an existing project.

  3. Create a class extending the class Sitecore.LayoutService.ItemRendering.ContentsResolvers.RenderingContentsResolver.

  4. 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;
    
            }
        }
    }
  5. Build and deploy your solution.

  6. Login to Sitecore and go to the Path: /sitecore/system/Modules/Layout Service/Rendering Contents Resolvers

  7. Insert an item with the template: Rendering Contents Resolver named Datasource With Children Items Resolver. Rendering Contents Resolver

  8. Add the field values as needed:

    • Type: The full type name of the custom rendering resolver of the class we created earlier. In this case, it will be JSSProject.Resolvers.DatasourceWithChildrenResolver, JSSProject.
    • Include Server URL in Media URLs: It is self-explanatory and recommended to be set to true.
    • Use Context Item: The layout service will use the context item, instead of the datasource item if set to true.
    • Rendering Contents Resolver Parameters: Key-Value parameters that will be passed to the resolver.
    • Item Selector Query: This will be a query for fetching the needed items. We should be able to filter out items here too. In this case, it will be ./*. DatasourceWithChildrenResolver
  9. Go to your rendering item, and change the value for the field Rendering Contents Resolver to the Custom Rendering Contents Resolver we created. index1686314483831

  10. Now, go to the datasource template and add the fields as required. I will be adding a field named cardListHeading to my CardList template.

  11. Go to your datasource item, and fill the values for the fields created. index1686314785460

  12. Save and publish to clear the cache.

  13. 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"
                                  }
                                }
                              }
                            }
                          ]
                        }
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    }
  14. 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);
    
  15. Save and reload your page.

  16. Your changes should reflect in the front end. index1686315126406

Happy Sitecoring!

Published Jun 9, 2023

Sitecore MVP Technology 2024-23. Web Developer with rich experience in Sitecore and ASP.NET MVC.