Implement folding

The Coveo Quantic library lets you display folded search results with any level of nesting. Folded results are search results that have a parent-child relationship. This article explains how to build hierarchical result lists using the QuanticFoldedResultList component.

Quantic folded results

For results with no parent-child relationship, the QuanticFoldedResultList component functions exactly like a standard QuanticResultList:

<template>
  <!-- ... -->
  <c-quantic-search-interface engine-id={engineId}>
    <!-- ... -->
    <c-quantic-folded-result-list engine-id={engineId}></c-quantic-folded-result-list>
    <!-- ... -->
  </c-quantic-search-interface>
  <!-- ... -->
</template>

In addition to rendering folded results, the QuanticFoldedResultList component also exposes the following optional attributes that let you customize your result folding implementation:

Prerequisites

Before you push data to the Coveo index, make sure that the data that you’re working with already has established parent-child relationships. Some data may have included these relationships when it was collected. If not, you need to build your own relationship graph.

Once your data has established parent-child relationships, you need to create the proper folding fields for the target items. After that’s done, you can push the data to your Coveo organization.

You may want to review the Coveo Level Up lesson on using result templates in Quantic. In particular, you need to be familiar with the following:

  • How to define an event handler to register your result templates.

  • How to attach this handler to an onregisterresulttemplates event added inside the <template> element in your search interface component HTML file.

Step 1: Configure the search page HTML

In the search page HTML, replace the QuanticResultList component with the QuanticFoldedResultList component. The following code is from a working example of folded results, so it includes some stylistic and formatting elements. You can omit or change these to style the results differently.

<template>
  <div onregisterresulttemplates={handleResultTemplateRegistration}> 1
    <div class="search__grid">
      <c-quantic-search-interface engine-id={engineId} search-hub={searchHub}>
        <div class="slds-grid slds-grid_vertical slds-grid_align-center">
          <div class="slds-col">
            <div class="slds-grid slds-gutters_direct slds-wrap main slds-grid_align-center">
              <div class="slds-col slds-order_2 slds-large-order_1 slds-size_1-of-1 slds-large-size_3-of-12 facets_container slds-show_large">
                <c-quantic-facet-manager engine-id={engineId}>
                  <c-quantic-facet field="objecttype" label="Type" engine-id={engineId}></c-quantic-facet>
                  <c-quantic-facet display-values-as="link" field="filetype" label="File Type" engine-id={engineId}></c-quantic-facet>
                  <c-quantic-facet display-values-as="link" field="source" label="Source" engine-id={engineId}></c-quantic-facet>
                </c-quantic-facet-manager>
              </div>
              <div class="slds-col slds-order_1 slds-large-order_2 slds-size_1-of-1 slds-large-size_6-of-12">
                <div class="slds-grid slds-var-m-top_small">
                  <c-quantic-summary
                    class="slds-var-m-vertical_x-small slds-small-size_8-of-12 slds-large-size_7-of-12"
                    engine-id={engineId}>
                  </c-quantic-summary>
                  <c-quantic-sort
                    class="slds-var-m-vertical_xxx-small slds-large-size_5-of-12 slds-show_large"
                    engine-id={engineId}>
                  </c-quantic-sort>
                  <div class="slds-small-size_4-of-12 slds-clearfix slds-hide_large">
                    <div class="slds-float_right">
                      <c-quantic-refine-toggle engine-id={engineId} full-screen></c-quantic-refine-toggle>
                    </div>
                  </div>
                </div>
                <c-quantic-folded-result-list engine-id={engineId}></c-quantic-folded-result-list> 2
                <div class="slds-var-m-vertical_medium">
                  <c-quantic-pager engine-id={engineId}></c-quantic-pager>
                </div>
              </div>
            </div>
          </div>
        </div>
      </c-quantic-search-interface>
    </div>
  </div>
</template>
1 Make sure to wrap your interface in a <div> element which sets onregisterresulttemplates={handleResultTemplateRegistration}. You will define the handleResultTemplateRegistration event handler in the component JavaScript file (see Step 4).
2 Use the QuanticFoldedResultList component to render folded results.

Step 2: Create the result templates

A QuanticFoldedResultList requires one or more QuanticResultTemplates to display the results. You’ll need to create separate result templates for the parent and child results. We recommend that you put these template files in a resultTemplates folder in your Lightning component folder.

The parent template must include a children slot. This slot contains the QuanticResultChildren component which renders the child results.

If you expect to have nested child results, your child template will also need to include a children slot with its own QuanticResultChildren component. You can use a single template for every nested level of child results, or you can create separate templates for different levels. The example below includes one template for all child result levels.

In fact, the only difference between the example templates is an extra <div> element on the parent template which adds a border below each parent group. However, in your own implementation, you may want to style the parent and child results differently.

Parent template

<template>
  <div class="slds-border_bottom">
    <c-quantic-result-template>
      <c-quantic-result-label slot="label" result={result}></c-quantic-result-label>
      <div slot="badges" class="slds-grid slds-grid_vertical-align-center slds-m-vertical_xx-small slds-m-right_small">
        <div class="slds-m-right_xx-small">
          <c-quantic-result-badge variant="recommended" result={result}></c-quantic-result-badge>
        </div>
        <c-quantic-result-badge variant="featured" result={result}></c-quantic-result-badge>
      </div>
      <p slot="date" class="slds-size_xx-small">
        <lightning-formatted-date-time value={result.raw.date}></lightning-formatted-date-time>
      </p>
      <div slot="title">
        <c-quantic-result-link result={result} engine-id={engineId}></c-quantic-result-link>
      </div>
      <div slot="excerpt">{result.Excerpt}</div>
      <div slot="children"> 1
        <c-quantic-result-children engine-id={engineId}
          template-id="myChildTemplate"
          collection={collection}
          folded-result-list-controller={foldedResultListController}
          result-templates-manager={resultTemplatesManager}>   2 3 4
        </c-quantic-result-children>
      </div>
    </c-quantic-result-template>
  </div>
</template>
1 The children slot is required to make a result template display child results.
2 engineId is defined in your component JavaScript file (see Step 4).
3 templateId is the ID of the template which is used to display the child results. The value you set here is used to create a condition for child results (see Step 4).
4 collection, foldedResultListController, and resultTemplatesManager are defined in the JavaScript file of the QuanticResult component.
Important

engineId, collection, templateId, foldedResultListController, and resultTemplatesManager are required properties of the QuanticResultChildren component.

Child template

<template>
  <c-quantic-result-template>
    <c-quantic-result-label slot="label" result={result}></c-quantic-result-label>
    <div slot="badges" class="slds-grid slds-grid_vertical-align-center slds-m-vertical_xx-small slds-m-right_small">
      <div class="slds-m-right_xx-small">
        <c-quantic-result-badge variant="recommended" result={result}></c-quantic-result-badge>
      </div>
      <c-quantic-result-badge variant="featured" result={result}></c-quantic-result-badge>
    </div>
    <p slot="date" class="slds-size_xx-small">
      <lightning-formatted-date-time value={result.raw.date}></lightning-formatted-date-time>
    </p>
    <div slot="title">
      <c-quantic-result-link result={result} engine-id={engineId}></c-quantic-result-link>
    </div>
    <div slot="excerpt">{result.Excerpt}</div>
    <div slot="children"> 1
      <c-quantic-result-children engine-id={engineId}
        template-id="myChildTemplate"
        collection={collection}
        folded-result-list-controller={foldedResultListController}
        result-templates-manager={resultTemplatesManager}>   2 3 4
      </c-quantic-result-children>
    </div>
  </c-quantic-result-template>
</template>
1 The children slot is required to make a result template display child results.
2 engineId is defined in your component JavaScript file (see Step 4).
3 templateId is the ID of the template which is used to display the child results. The value you set here is used to create a condition for child results (see Step 4). This example uses the same result template for all levels of nested child results, so this templateId is the same as the one defined in the parent template. If you have separate result templates for different levels of nested child results, then you would use a different templateId here to create discrete conditions for each level.
4 collection, foldedResultListController, and resultTemplatesManager are defined in the JavaScript file of the QuanticResult component.
Important

engineId, collection, templateId, foldedResultListController, and resultTemplatesManager are required properties of the QuanticResultChildren component.

Step 3: Import the result templates

To use the new parent and child result templates, you need to import them in the component JavaScript file.

import parentTemplate from './resultTemplates/parentTemplate.html';
import childTemplate from './resultTemplates/childTemplate.html';

Step 4: Register the result templates

You need to register the result templates in the component JavaScript file using the Coveo Headless ResultTemplatesManager. The following example is the complete JavaScript file from a working implementation of result folding.

import { LightningElement, api } from 'lwc';
import parentTemplate from './resultTemplates/parentTemplate.html';
import childTemplate from './resultTemplates/childTemplate.html';

export default class FoldingTest extends LightningElement {
  @api engineId = 'folding-test-engine';
  @api searchHub = 'folding-test-hub';

  handleResultTemplateRegistration(event) { 1

    const resultTemplatesManager = event.detail; 2

    const isParent = CoveoHeadless.ResultTemplatesHelpers.fieldMustMatch( 3
      'filetype',
      ['slackmessage']
    );

    const isChild = CoveoHeadless.ResultTemplatesHelpers.fieldMustMatch( 4
      'quantic__templateId',
      ['myChildTemplate']
    );

    resultTemplatesManager.registerTemplates( 5
      {
        content: childTemplate,
        conditions: [isChild], 6
        priority: 1 7
      },
      {
        content: parentTemplate,
        conditions: [isParent]
      }
    );

  }

}
1 Define an event handler that you have already attached to your component HTML file on the onregisterresulttemplates event.
2 The detail property contains a result template manager. Store it in a variable so you can use it a few lines below.
3 Create a condition that matches a known property which is common to all parent items.
4 Create a condition that matches a known property which is common to all child items. In this example, the quantic__templateId property is myChildTemplate. This value is defined in the QuanticResultChildren components in the parent and child result templates. If you have multiple child templates with different IDs, you’ll need a separate condition for each.
5 Register the result template on the result template manager.
6 These two lines tie each template to a specific condition.
7 Set the priority of the result template. The lowest possible priority is 0. The larger this value, the higher the priority assigned to the result template. If the conditions of multiple templates are satisfied by a given result, the template with the highest priority is selected. If multiple templates have equal priority, the first template registered is selected.

Save and push your changes to your Salesforce organization.

Refresh your Experience Builder and open the page which contains your search interface in Preview mode. When you select the property that you associated with parent items in the relevant facet, you’ll see the folded results.