Step 6 - Result Templates

Even in a bare-bones search page, end users normally expect each search result to render itself in a uniquely relevant fashion, according to its type. For instance, a YouTube search result should probably display a preview of the video as well as its length, number of views, etc. However, including the exact same information in an Email search result would be an obvious design mistake.

In this step of the tutorial you will learn how to create your own result templates in order to customize the way search results appear in your search page.

If you significantly modified the ./bin/index.html page in previous steps of this tutorial, you can undo these changes by rebuilding the project. To do so, run the following command line from the top of the tutorial project folder:

npm run build

Default Result Templates

The Coveo JavaScript Search Framework includes a set of default result templates. Currently,  you are using those templates in your tutorial search page.

In the ./bin/index.html page head, you can see the following reference:

<script src="js/templates/templates.js"></script>

This line references the default result templates.

In the ./bin/index.html page body, you can see that there are two ResultList components, which look like this:

<div class="CoveoResultList" data-layout="list" data-wait-animation="fade" data-auto-select-fields-to-include="true"></div>
<div class="CoveoResultList" data-layout="card" data-wait-animation="fade" data-auto-select-fields-to-include="true"></div>

You will notice that the only difference between both component is their data-layout value. This value determines the way the results should be displayed (see Result Layouts).

In this tutorial, you will only be creating result templates for the list layout, as it is the most commonly used.

When you want to specify a custom result template, you need to add it inside a ResultList HTML element. The result template itself must be inside an HTML script tag.

In the ./bin/index.html page, the ResultList components currently contain no script tag, which means there are no custom result templates, and since there is a reference to the default result templates in the page head, the framework applies the default result templates to display the search results.

If you remove the <script src="js/templates.js"></script> reference from the page head, you will notice that the framework still uses a very basic result template to display the search results. This template is defined in the Coveo JavaScript Search Framework code itself so that the results can at the very least render themselves.

You can experiment by removing the <script src="js/templates.js"></script> line from the page header to see the difference.

Result Properties

When a query to the REST Search API returns, you can inspect the results property in the JSON response to see the content of each result.

Some of the most important result properties are:

  • title: The title of the current result.
  • clickUri: The clickable URI of the item. You should use this property when creating an anchor to reach the item. Do not confuse this property with the uri property, which is an internal structure that Coveo uses to uniquely identify the item in the index.
  • excerpt: An excerpt of the item. The index generates this to highlight important keywords in the item, depending on the query. Some types of items, such as images, do not have an excerpt.
  • raw: A JSON containing all available fields and metadata pairs for the current result.

The raw property is especially important and will often be referred to within this tutorial and further documentation.

For more information on these and other result properties, see the IQueryResult interface.

Create Your Own Templates

You can add your own result templates by inserting script tags inside a ResultList HTML element (see Using Result Templates).

<div class="CoveoResultList" data-layout="list" data-wait-animation="fade" data-auto-select-fields-to-include="true">
  <script type="text/underscore" class="result-template" data-field-filetype="YouTubeVideo">
    <!-- ... -->
  </script>
</div>

The order of the result template scripts is very important, as it determines the order of evaluation (see Understanding Which Result Template Loads for a Result).

Any result template you create can either be an HTML or an Underscore result template.

Q: Which type of result template should I use: HTML, or Underscore?

A: Both have their own advantages and inconveniences. Generally speaking, HTML result templates are simpler, whereas Underscore result templates are more powerful.

Underscore result templates will be used as examples in the rest of this tutorial step as they are more complex, and therefore important to explain.

When using the JavaScript Search Framework inside Coveo for Salesforce, you are encouraged to use HTML result templates (see Making the Coveo Lightning Components Lightning Locker Compliant).

For more information, see HTML Result Template and Underscore Result Template.

About the Condition Property

Prior to the March 2017 Release (v1.2359.7), the data-condition property was used to specify the condition that the result must meet in order to load the result template.

<div class="CoveoResultList" data-layout="list" data-wait-animation="fade" data-auto-select-fields-to-include="true">
  <script type="text/underscore" class="result-template" data-condition="raw.filetype==='YouTubeVideo'">
    <!-- ... -->
  </script>
</div>

It is now recommended to use the data-field-[fieldName] property (see Choosing the Appropriate Method).

<div class="CoveoResultList" data-layout="list" data-wait-animation="fade" data-auto-select-fields-to-include="true">
  <script type="text/underscore" class="result-template" data-field-filetype="YouTubeVideo">
    <!-- ... -->
  </script>
</div>

This is even more important when using the JavaScript Search Framework inside Coveo for Salesforce (see Making the Coveo Lightning Components Lightning Locker Compliant).

Result Template Components

The Coveo JavaScript Search Framework offers some components that should only be used inside result templates. These components cover most basic use cases encountered when creating result templates (see Customizing Result Templates).

Why should I use the ResultLink component?

In most result templates, you will likely want to offer some sort of link that the end user can click to reach the original item. While it might be tempting to output a simple anchor to do so, such practice will cause significant parts of the Coveo Analytics stack to stop working correctly.

As a matter of fact, a query is in large part deemed successful by the Coveo Analytics stack when the end user clicks on an item returned by the query.

The Coveo JavaScript Search Framework does not, and cannot, track every single anchor click in a result template as if it were an actual ResultLink component.

Consequently, you should always use the ResultLink component. Otherwise, you will need to take care of logging the correct analytics events yourself.

Basic Underscore Logic

When using Underscore templates, it is possible to execute arbitrary JavaScript code.

Underscore templates are evaluated with each query result being the context of execution.

Other than that, these templates are relatively straightforward (see Underscore.js - template).

// This outputs the non HTML-escaped field value.
<%= raw.someFieldValue %>
 
// This outputs the HTML-escaped field value.
<%- raw.someFieldValue %>
// You can also execute arbitrary JavaScript code by using <% %> tags.
<% if (raw.name != null) { %>             
  <div>Hello <%- raw.name %>!</div>
<% } %>

Template Composition

It is possible to re-use a single template in multiple templates by using the TemplateLoader component.

Outside of ResultList components, you will have to declare a result template that you want to use in multiple places. Then you can use this result template inside another one as in the following example:

<!-- This template will be used in multiple places. -->
<script type='text/underscore' class='result-template' id='MyReusedDateTemplate'>
  <div>
    <table class="CoveoFieldTable">
      <tr data-field="@date" data-caption="Date" data-helper="date"></tr>
    </table>
  </div>
</script>
 
<!-- ... -->
 
<div class="CoveoResultList" data-layout="list" data-wait-animation="fade" data-auto-select-fields-to-include="false">
  <!-- This is a template for images. -->
  <script type='text/underscore' class='result-template' data-field-filetype='Image'>
    <div>
      <a class='CoveoResultLink'></a>
      <img class='CoveoThumbnail'></img>
      <div class='CoveoTemplateLoader' data-template-id='MyReusedDateTemplate'></div>
    </div>
  </script>
 
  <!-- This is a template for YouTube videos. -->
  <script type="text/underscore" class="result-template" data-field-filetype='YouTubeVideo'>
    <div>
      <div class="CoveoYouTubeThumbnail"></div>
      <a class='CoveoResultLink'></a>
      <div class='CoveoExcerpt'></div>
      <div class='CoveoTemplateLoader' data-template-id='MyReusedDateTemplate'></div>
    </div>
  </script>
</div>

Q: Why must the “MyReusedDateTemplate” be declared outside of ResultList components?

A: Because you do not want this result template to be used as one of the main result templates. If you include it inside a ResultList component, it will be evaluated just like the other result templates, which means it could potentially load on its own.

You can put reusable result templates anywhere in your search page. As long as they match the required criteria for a result template (i.e., they have the correct class and type), they will be “loaded” by the framework and made available for other result templates to use.

Exercises

  • All exercises in this section should be done by modifying the tutorial search page under ./bin/index.html. The exercises should not be done by modifying the original search page under ./pages/index.html.
  • In order to actually see the results in your demo page, you must be running a webpack-dev-server (See Step 0 - Environment Setup).
  1. Create a result template that applies to every result for which the filetype field equals 'File'.

    • The result template needs to output a clickable ResultLink, as well as an Excerpt if it is available.
    • If the result is an image, the result template must output a Thumbnail.
    • The result template must also output a FieldTable containing the date of the item and its type.

Solution:

<script type='text/underscore' class='result-template' data-field-objecttype='File'>
  <div>
    <a class='CoveoResultLink'></a>
    <% if(excerpt != null) { %>
      <div class='CoveoExcerpt'></div>
    <% } %>
    <% if(raw.filetype == 'Image') { %>
      <div class='CoveoThumbnail'></div>
    <% } %>
      <table class='CoveoFieldTable'>
        <tr data-field='@date' data-caption='Date' data-helper='date'></tr>
        <tr data-field='@filetype' data-caption='File type'></tr>
      </table>
  </div>
</script>

What’s Next?

You should now proceed to Step 7 - Usage Analytics.