Skip to end of metadata
Go to start of metadata

You can take advantage of the Coveo JavaScript Search Framework event system to interact with the framework using external, event-driven code. There are two broad categories of events you can attach handlers to: global events and component events.

Base assumptions

Icon

All examples in this article assume that you include the following references in your search page:

The examples also assume that the id attribute of the root element of your search interface is search.

Attaching Event Handlers

The Coveo JavaScript Search Framework triggers regular DOM events. You can attach handlers to those events just as you would in the case of "standard" events (e.g., DOMContentLoadedclick, etc.).

Most of the time, you should register your Coveo JavaScript Search Framework event handlers on the root HTML element of your search interface. Some components trigger events on their own HTML element, but since those events bubble up, handlers registered on the root element can catch them as well.

Best practice

Icon

 You should always register Coveo JavaScript Search event handlers before the init call of your search interface.

Example - Attaching an event handler:

The following code excerpt registers a buildingQuery event handler on the root HTML element of your search interface.

Different ways to attach event handlers

Icon

There are three different ways to register Coveo JavaScript Search Framework event handlers (see Interacting with the Framework and Its Components):

  • Using "pure" JavaScript (document.addEventListener("[eventName]", function(e) { [ ... Code ... ] }));
  • Using the Dom helper class (Coveo.$$(root).on("[eventName]", function(e, args) { [ ... Code ... ] }));
  • Using the Coveo jQuery extension ($(root).on("[eventName]", function(e, args) { [ ... Code ... ] })).

For the sake of simplicity and uniformity, all examples in this article use the the on method of the Dom helper class to attach event handlers.

Embedding Event Handlers

When the Coveo JavaScript Search Framework triggers an event, listeners are notified in the order in which they were registered. Any Coveo component that needs to register its own event handlers does so when its constructor function is executed during the init call of the search interface. Therefore, the event handlers you register before the init call will normally be registered before any Coveo component has a chance to register its own event handlers.

In some specific cases, you may need to ensure that an event handler is registered at a later moment, though. For instance, you might want certain Coveo event handlers to be notified (and executed) before your own. You might also wish to ensure that an event handler is registered only when the end user performs a certain action (which triggers a certain event) in the search interface. These are instances of situations where you should embed event handlers.

Example - Attaching an embedded event handler:

The following code excerpt registers an embedded buildingQuery event handler on the root HTML element of your search interface.

The buildingQuery handler is embedded within an afterComponentsInitialization handler. This implies that the buildingQuery handler will only be registered when all Coveo components have registered their own event handlers.

Note

Icon

You could achieve a similar result by registering the buildingQuery event handler after the init call without embedding it in an afterComponentsInitialization handler. However, doing so is considered bad practice and can cause unexpected behavior in lazy component loading mode (see Lazy Versus Eager Component Loading).

Global Events

Global events have no direct association with any particular component. There are two types of global events in the Coveo JavaScript Framework: initialization events and query events.

Initialization Events

Initialization events are triggered during the execution of the init call of your search interface. Typically, you will attach handlers to those events to alter Coveo components before they are rendered, or to interact with the state object and the URL before the first query is launched. The initialization events are:

Event Flow

The following diagram displays the sequential flow of initialization events.

Handling Initialization Events

You must register all initialization event handlers before the init call of your search interface, otherwise they will have no effect.

Handling events in lazy component loading mode

Icon

 

Available in: Upcoming release

In lazy component loading mode, the init function starts by asynchronously downloading the code of each required component. Downloading a component code chunks is a non-blocking process during which the execution stack processing can resume. Once the code chunk of a certain component has finished downloading, the init function resumes and sequentially calls the constructor function of each future instance of this component. Then, the execution stack processing can resume, and so on until all components have been instantiated.

Therefore, in lazy component loading mode, it is possible to successfully register initialization event handlers (with the exception of beforeInitialization handlers) after the init call. Such handlers will be registered at some point after the beforeInitialization event, and before the afterComponentsInitialization event. There is no easy way to tell precisely when the event handler will be registered, though. Consequently, registering initialization event handlers after the init call is considered bad practice.

In conclusion, you should always handle events in lazy component loading mode precisely as you would in eager component loading mode.

Example - Adding a filter to the query:

The following code excerpt shows how you could attach a handler to the afterInitialization event to specify a hidden query (hq) in the state object.

In this example, an advanced expression which requires results to be English PDF files containing the Coveo keyword is added to the query (see Coveo Cloud Query Syntax Reference).


Code Samples

Modifying Search Interface Options

The following code excerpt shows how you could use a beforeInitialization event handler to modify a set of SearchInterface options when a certain condition is met.

In this example, the query result excerpts length is shortened, and a special query pipeline is applied when the end user is accessing the search page from a mobile device.

The userIsOnMobileDevice function

Icon

The userIsOnMobileDevice function has voluntarily been left unimplemented in this code sample. If you want to try this sample, you should provide your own implementation, or simply ensure that the function returns an arbitrary boolean value.


Selecting a Tab and Facet Values

This example assumes that you include the following markup in your search page:

The following code excerpt shows how you could dynamically interact with the state object and with component instances using an afterInitialization event handler.

In this example, when the search page loads, the Messages tab is automatically selected. Then, the current year is selected in the Year facet, and the current month, as well as the two preceding months, are selected in the Months facet. These selections are made before the initial query (assuming the autoTriggerQuery option of the SearchInterface is set to true), and do not themselves trigger new queries; they simply serve as additional "filters" for the initial query.

Query Events

Query events are triggered during the execution of a search request to the Coveo Search API. Typically, you will attach handlers to those events to:

  • Cancel the query;
  • Alter the appearance or behavior of a component before, during, or after the query;
  • Modify the outgoing query and the incoming result set;
  • Handle query errors and result sets that contain no results;
  • Alter the way the query results are rendered.

The query events are:

Query event arguments

Icon

All query event handlers receive a certain object as an argument. For instance, all doneBuildingQuery event handlers receive an IDoneBuildingQueryEventArgs object as an argument. You can get or set the attributes of this object to interact with the query or with the results.

See the reference documentation of each individual query event for information about the object its handlers receive as an argument.

Event Flow

The following diagram displays the sequential flow of query events.

Additional query events

Icon

This diagram does not include the duringFetchMoreQuery, preprocessMoreResults, and fetchMoreSuccess events.

These events are respectively equivalent to the duringQuery, preprocessResults, and querySuccess events, except they are triggered when certain components need to perform their own queries to fetch additional results (e.g., for infinite scroll, folding, etc.).

Handling Query Events

In theory, you can register query event handlers either before or after the init call of your search interface.

Registering a query event handler before the init call implies that this handler will be registered before any component constructor function is called. Registering the same handler after the init call means that the handler will be registered after all component constructors have been executed. This is perfectly equivalent to embedding the handler inside an afterInitialization handler.

Best practice

Icon

Registering query event handlers after the init call can cause unexpected behavior in lazy component loading mode (see Lazy Versus Eager Component Loading).

Therefore, the best practice is to always register query event handlers before the init call, embedding event handlers to enforce a sequential registration flow when necessary (see Embedding Event Handlers).

Code Samples

Modifying the Appearance of an Element

This example assumes that you include the following markup in your search page:

The following code excerpt shows how you could use newQuery, queryError, and querySuccess event handlers to modify the appearance of an HTML element depending on the current state of the query.

In this example, when a new query is triggered, the element displays the Loading... text. When the query successfully returns (whether or not it actually contains results), it displays the Done! text. If the query fails (because of a search endpoint configuration error, for instance), it displays the Error. text.

If you run this code sample, you should see something like this at the top of your search page:

Toggling the Query Cache

This example assumes that you include the following markup in your search page:

By default, the Coveo Search API tries to return cached query results when a search request is triggered. This means that sending the same search request again and again over a brief period of time does not necessarily trigger a large number of complete queries to the Coveo index, since the results are already available (and likely still up-to-date) in cache.

The following code excerpt shows how you could use a buildingQuery event handler to allow the end user to activate or deactivate query cache in your search page by interacting with a checkbox input.

In this example, the checkbox state is saved in local storage so that when the end user reloads the search page, the previously selected state is automatically reapplied.

Since it is embedded within an afterInitialization handler, this buildingQuery handler will only be registered after each Coveo component has registered its own event handlers, and the hash portion of the URL has been applied to the state object. Consequently, this handler will be notified last when the buildingQuery event is triggered. This ensures that no internal Coveo event handler can possibly "override" this handler.

If you run this code sample, you should see a Disable Query Cache checkbox input in your search page:

If you leave the box unchecked and launch a query whose results are already available in cache (the initial query, for instance), you should see something like this when you inspect the query response:

If you check the box and try sending the same query again, the response should now contain something similar to this:

Replacing Special Characters in the Query

The Coveo query syntax allows the end user to enter complex query expressions in the query box (see Coveo Cloud Query Syntax Reference). You can decide whether to completely enable or disable query syntax in your search page by setting the enableQuerySyntax option value of your Searchbox accordingly.

In certain cases, you might need to disable only some of the query syntax features (e.g., setting the enableQuerySyntax option to true, but ignoring certain special characters which could otherwise be interpreted as Coveo query syntax, such as $). While the Coveo Search API offers no "clean" way to do this in the query pipeline, it is possible (although not ideal) to modify the queryBuilder to artificially achieve this kind of query syntax granularity.

Query syntax and the Coveo JavaScript Search Framework v2.x

Icon

Available in: Upcoming release

The enableQuerySyntax option defaults to false in the Coveo JavaScript Search Framework v2.x (its default value was true in v1.x).

Moreover, end user preferences can override the enableQuerySyntax option value in v2.x.

The following code excerpt shows how you could use a doneBuildingQuery event handler to remove certain special characters from the basic query expression before sending it to the Coveo Search API.

 In this example, the $ character is replaced by the empty string.


Modifying the Query Results

The following code excerpt shows how you could use a preprocessResults event handler to modify the results before the ResultList component renders them.

In this example, the handler converts the title of all results whose objecttype field value is User to uppercase.

Icon

Client side manipulations of query results such as this one are "quick and dirty" ways to fix problems and inconsistencies which actually reside within the index itself. If you find yourself resorting to this kind of result manipulation very often in your search page, you should probably consider making adjustments in the index (e.g., adding or modifying pre and post indexing pipeline extensions, field mapping rules, etc.).

Displaying Query Result Information

The following code excerpt shows how you could use a querySuccess event handler to interact with the current page of query results.

In this example, when the query successfully returns, the handler renders a list containing the number of occurrences of each source type present in the current page of results.

If you run this code sample, you should now see something like this at the top of your result list:

Component Events

Component events are usually triggered by specific components. The following Coveo JavaScript Search Framework component have their own sets of events:

Note

Icon

This article only discusses the most commonly used ResultList events, and the changeAnalyticsCustomData Analytics event.

See the reference documentation of the aforementioned components for more information on their respective events.

Analytics Events

changeAnalyticsCustomData

The changeAnalyticsCustomData event is triggered right before sending the custom data and metadata of an analytics event to the Coveo Analytics REST service. All changeAnalyticsCustomData event handlers receive an ChangeAnalyticsCustomDataEventArgs as an argument, which extends the IChangeableAnalyticsDataObject interface. You can attach handlers to this event to read and modify the information that is about to be sent to the Coveo Analytics REST service.

Argument Object
Name
Description
typeThe type of event that is being logged. Can be SearchEvent, ClickEvent, or CustomEvent
metaObject

The custom event metadata. All key-value pairs included in this object will be sent as custom metadata to the Coveo Analytics service, and can then be used to create custom dimensions in analytics reports.

language

The language of the search interface.

By default, this value is populated by the localization file used by the search interface.

originLevel1

The high-level origin of the analytics event. Typically, this is the name of the current search hub, or a name which can uniquely identify the search page.

Default value is default.

originLevel2

The mid-level origin of the analytics event.

By default, this value is populated by the currently selected tab.

originLevel3

The low level origin of the analytics event. Typically, this is the HTTP identifier of the page from which the event originates.

By default, this property is left empty.

resultData

(ClickEvent only)

When the analytics event type is ClickEvents, the event object contains an additional attribute.

You can take advantage of the resultData object to push more analytics data from the results that have been clicked.

Example:

You want to include the value of the product field for the clicked result in the pushed analytics data:

ResultList Events

The ResultList component can trigger several events. Two of these events are especially useful: newResultDisplayed (singular: "result") and newResultsDisplayed (plural: "results"). You can attach handlers to these events to alter the appearance of rendered query results.

ResultList events versus result templates

Icon

In most cases, you can simply rely on the result template evaluation mechanism rather than attaching your own handlers to the newResultDisplayed or newResultsDisplayed events (see Result Templates).

Event Flow

The following diagram displays the part of the sequential query event flow where the ResultList component triggers the newResultDisplayed and newResultsDisplayed events (see Query Events - Event Flow for the complete diagram).

In summary, the ResultList component triggers the newResultDisplayed event each time it renders a result. However, it triggers the newResultsDisplayed event only once, when all results have been rendered.

A word of caution about this diagram

Icon

Other querySuccess event handlers may have been registered before (and after) the ResultList querySuccess event handler.

This means that in the previous diagram, the querySuccess event could trigger other processes, which would either be executed before or after the ResultList rendering process, depending on when their corresponding event listeners were registered.

Handling the newResultDisplayed Event

All newResultDisplayed event handlers receive an IDisplayedNewResultEventArgs as an argument. This object includes the current IQueryResult (the result object) as well as the current HTMLElement (the item object). Typically, you will want to get values from the result object and set values in the item object to alter the rendering of the results.

As usual, you should always register your newResultDisplayed event handlers before the init call of your search interface.

Code Sample

Example - Modifying the rendering of each result:

The following code excerpt shows how you could use a newResultDisplayed event handler to modify the appearance of each result in the result list.

In this example, the handler modifies the HTML of each rendered ResultLink component so that it displays the name of the source before the result title.

Handling the newQueryResultsDisplayed Event

All newQueryResultsDisplayed event handlers receive a recursive representation (tree) of the source (the srcElement object) and target (the target object) HTML elements of the ResultList. Typically, you will want to get values from the srcElement object and set values in the target object to alter the rendering of the results.

As usual, you should always register your newResultsDisplayed event handlers before the init call of your search interface.

newResultDisplayed versus newResultsDisplayed

Icon

You can accomplish the exact same thing using either a newResultDisplayed or a newResultsDisplayed event handler. Attaching a handler to the newResultDisplayed event is often slightly easier (and cleaner) though, since it does not require you to write a loop when you need to iterate through each element in the result list.

Code Sample

Example - Modifying the rendering of each result:

The following code excerpt shows how you could use a newResultDisplayed event handler to modify the appearance of each result in the result list.

In this example, the handler modifies the HTML of each rendered ResultLink component so that it displays the name of the source before the result title.

  • No labels

2 Comments

  1. Is there an event that fires when the "infinite page scroll" request to loads more items?  I'm finding that "buildQuery" fires once on the initial query, but not the content streams in.  Thanks!

    1. There is no event fired on the fetch more method. There are events triggered when new results are displayed though.