-
Tutorials
- 0: Environment Setup
- 1: Basic Configuration, Options, and Markup
- 2: Interact With the Search Interface and Component Instances
- 3: Understanding the Event System
- 4: Modify the Query
- 5: Result Templates
- 6: Usage Analytics
- 7: Interact With Component States
- 8: Configure Your Own Search Endpoint
- 9: Advanced Integration With Custom TypeScript Component (Configuration)
- 10: Advanced Integration With Custom TypeScript Component (Implementation)
JavaScript Search Framework Tutorial 5: 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 example, 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 tutorial, you’ll 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 tutorials, you can undo these changes by rebuilding the project. To do so, run the following command line from the root 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’re 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’ll notice that the only difference between both component is their data-layout
value. This value determines the way the results should be displayed (see JavaScript Search Framework Result Layouts).
In this tutorial, you’ll only be creating result templates for the list
layout, as it’s 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’s 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’ll 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. Don’t confuse this property with theuri
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, don’t 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.
<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 the Condition Evaluation Mechanism).
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 templates are simpler, whereas Underscore templates are more flexible.
Underscore result templates will be used as examples in the rest of this tutorial step as they’re more complex, and therefore important to explain.
When using the JavaScript Search Framework inside Coveo for Salesforce, you’re encouraged to use HTML result templates (see Making the Coveo Lightning Components Lightning Locker Compliant).
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 (see Using JavaScript Conditions).
<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>
We now recommend that you use the data-field-
property (see Using Field-Based Conditions).
<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 of the basic use cases encountered when creating result templates.
Why should I use the ResultLink
component?
In most result templates, you’ll 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 doesn’t, and can’t, 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’ll need to take care of logging the correct analytics events yourself.
Basic Underscore Logic
When using Underscore templates, it’s 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’s possible to re-use a single template in many templates by using the TemplateLoader
component.
Outside of ResultList
components, you’ll have to declare a result template that you want to use in many places. Then you can use this result template inside another one as in the following example:
<!-- This template will be used in many 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 don’t 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 shouldn’t be done by modifying the original search page under./pages/index.html
. -
To actually see the results in your demo page, you must be running a webpack-dev-server (See JavaScript Search Framework Tutorial 0: Environment Setup).
-
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 anExcerpt
if it’s 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 JavaScript Search Framework Tutorial 6: Usage Analytics.