--- title: Events slug: '417' canonical_url: https://docs.coveo.com/en/417/ collection: javascript-search-framework source_format: adoc --- # Events You can take advantage of the [Coveo JavaScript Search Framework](https://docs.coveo.com/en/187/) 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](https://docs.coveo.com/en/417#global-events)_ and _[component events](https://docs.coveo.com/en/417#component-events)_. > **Note** > > **Base assumptions** > > ```html ``` > > The examples also assume that the `id` attribute of the root element of your [search interface](https://docs.coveo.com/en/2741/) is `search`. ## Attaching event handlers The JavaScript Search Framework triggers regular DOM events. You can attach handlers to these events just as you would with "standard" events (for example, `DOMContentLoaded`, `click`, etc.). Register your Framework event handlers on the root HTML element of your search interface. Some components trigger events on their own HTML element, but since these events bubble up, handlers registered on the root element can catch them as well. > **Leading practice** > > Always register the Framework event handlers before the `init` call of your search interface. **Example** The following code excerpt registers a `buildingQuery` event handler on the root HTML element of your search interface. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("buildingQuery", function(e, args) { // Some code to execute when the queryBuilder has just been instantiated... }); Coveo.init(root); }); ``` > **Note** > > **Different ways to attach event handlers** > > There are three different ways to [register Framework event handlers](https://docs.coveo.com/en/369/): > > * 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 ... > ] })+`). > > Examples in this article use the `on` method of the `Dom` helper class to attach event handlers. ## Embedding event handlers When the 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 that 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. For example, you might want certain Coveo event handlers to be notified (and executed) before your own. You might also want to ensure that an event handler is only registered when the end user performs a given action (which triggers a specific event) in the search interface. In these situations, 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. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); // This handler will be registered after all components have registered their own handlers. Coveo.$$(root).on("afterComponentsInitialization", function() { Coveo.$$(root).on("buildingQuery", function(e, args) { // Some code to execute when the `queryBuilder` has just been instantiated... }); }); Coveo.init(root); }); ``` ## Global events _Global_ events have no direct association with any particular component. There are two types of global events in the JavaScript Search 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 these events to alter Coveo components before they're rendered, or to interact with the `state` object and the URL before the first [query](https://docs.coveo.com/en/231/) is launched. The initialization events are: * `beforeInitialization` * `afterComponentsInitialization` * `restoreHistoryState` * `afterInitialization` #### 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. > **Note** > > **Handling events in lazy component loading mode** > > 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's possible to successfully register initialization event handlers (except for `beforeInitialization` handlers) after the `init` call. > Such handlers will be registered at some point after the `beforeInitialization` event, and before the `afterComponentsInitialization` event. > There's no easy way to tell precisely when the event handler will be registered, though. > Because of this, you should avoid registering initialization event handlers after the `init` call. > > 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](https://docs.coveo.com/en/2736/) 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 is added to the query. It requires results to be English PDF files that contain the [keyword](https://docs.coveo.com/en/2738/) `Coveo` (see [Query syntax](https://docs.coveo.com/en/1552/)). ```javascript document.addEventListener("DOMContentLoaded", function () { Coveo.SearchEndpoint.configureSampleEndpointV2(); var root = document.querySelector("#search"); Coveo.$$(root).on("afterInitialization", function() { Coveo.state(root, "hq", "(@filetype==pdf) (@language==English) (Coveo)"); }); Coveo.init(root); }); ``` #### 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 specific condition is met. In this example, when the end user accesses the search page from a mobile device, the query result excerpt length is shortened and a special [query pipeline](https://docs.coveo.com/en/180/) is applied. > **Important** > > The `userIsOnMobileDevice` function isn't implemented in this code sample. > To try it, you must provide your own implementation or ensure that the function returns an arbitrary Boolean value. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); /** * Indicates whether the end user is on a mobile device. * * @returns {boolean} `true` if the end user is on a mobile device; `false` otherwise. */ var userIsOnMobileDevice = function() { // ... Implementation ... }; /** * Sets the `excerptLength` and `pipeline` options of the `SearchInterface` to some arbitrary "mobile" values. * * @param rootElement The root element of the search interface. */ var setMobileOptionValues = function(rootElement) { rootElement.setAttribute("data-excerpt-length", "100"); rootElement.setAttribute("pipeline", "mobileQueryPipeline"); }; root = document.querySelector("#search"); Coveo.$$(root).on("beforeInitialization", function() { if (userIsOnMobileDevice()) { setMobileOptionValues(root); } }); Coveo.init(root); }); ``` ##### Selecting a tab and facet values This example assumes that you include the following markup in your search page: ```html [ ... ]
[ ... ]
[ ... ] ``` 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, in the **Year** [facet](https://docs.coveo.com/en/198/), the current year is selected. Finally, in the **Months** facet, the current month and two preceding months are selected. These selections are made before the initial query (assuming the `autoTriggerQuery` option of the `SearchInterface` is set to `true`), and don't themselves trigger new queries; they simply serve as additional "filters" for the initial query. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); /** * Selects the **Messages** tab by modifying the `state` object. * * @param rootElement The root element of the search interface. */ var selectMessagesTab = function(rootElement) { if (Coveo.$$(document).find(".CoveoTab[data-id='Messages']") !== null) { Coveo.state(rootElement, "t", "Messages"); } }; /** * Selects the current year value in the **Year** facet instance. */ var selectCurrentYearFacetValue = function() { var yearFacetInstance = Coveo.get(Coveo.$$(document).find(".CoveoFacet[data-title='Year']")); if (yearFacetInstance !== null) { var thisYear = new Date().getFullYear().toString(); yearFacetInstance.selectValue(thisYear); } }; /** * Selects values corresponding to this month and the two previous months in the **Months** facet instance. */ var selectRecentMonths = function() { var monthFacetInstance = Coveo.get(Coveo.$$(document).find(".CoveoFacet[data-title='Month']")); if (monthFacetInstance !== null) { var thisMonth = new Date().getMonth(); for (var i=thisMonth-2; i <= thisMonth; i++) { monthFacetInstance.selectValue("0" + i.toString()); } } }; var root = document.querySelector("#search"); Coveo.$$(root).on("afterInitialization", function() { selectMessagesTab(root); selectCurrentYearFacetValue(); selectRecentMonths(); }); Coveo.init(root); }); ``` ### 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: * `newQuery` * `buildingQuery` * `doneBuildingQuery` * `duringQuery` / `duringFetchMoreQuery` * `queryError` * `preprocessResults` / `preprocessMoreResults` * `noResults` * `querySuccess` / `fetchMoreSuccess` * `deferredQuerySuccess` > **Note** > > **Query event arguments** > > All query event handlers receive a certain object as an argument. > For example, 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. > **Important** > > **Additional query events** > > This diagram doesn't include the `duringFetchMoreQuery`, `preprocessMoreResults`, and `fetchMoreSuccess` events. > > These events are equivalent to the `duringQuery`, `preprocessResults`, and `querySuccess` events respectively, except they're triggered when certain components must perform their own queries to fetch additional results (for example, 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 the handler will be registered before any component constructor functions are called. Registering the same handler after the `init` call means that it will be registered after all of the component constructors have been executed. This is equivalent to embedding the handler inside an `afterInitialization` handler. > **Leading practice** > > You should always register query event handlers before the `init` call. > You can [embed event handlers](#embedding-event-handlers) to enforce a sequential registration flow, when necessary. #### Code samples ##### Modifying the appearance of an element This example assumes that you include the following markup in your search page: ```html [ ... ]
Done!
Error.
Loading...
[ ... ] ``` Depending on the current state of the query, the following code excerpts show how you could use `newQuery`, `queryError`, and `querySuccess` event handlers to modify the appearance of an HTML element. In this example, when a new query is triggered, the element displays the **Loading**. text. When the query successfully returns (whether it actually contains results), it displays the **Done!** text. If the query fails (because of a search endpoint configuration error, for example), it displays the **Error**. text. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); var hiddenClass = "currently-hidden"; /** * Indicates whether the target HTML element is currently hidden by verifying whether it has the corresponding * CSS class. * * @param element The target HTML element. * * @returns {boolean} `true` if the HTML element is currently hidden; `false` otherwise. */ var isCurrentlyHidden = function(element) { return element.classList.contains(hiddenClass); }; /** * Toggles the visibility of the target HTML element by adding or removing the corresponding CSS class. * * @param element The target HTML element. */ var toggleElementVisibility = function(element) { if (isCurrentlyHidden(element)) { element.classList.remove(hiddenClass); } else { element.classList.add(hiddenClass); } }; root = document.querySelector("#search"); Coveo.$$(root).on("newQuery", function(e, args) { // If the previous query returned an error, hide the `query-error` element when launching the new query. var error = document.querySelector("#query-error"); if (!isCurrentlyHidden(error)) { toggleElementVisibility(error); } toggleElementVisibility(document.querySelector("#query-done")); toggleElementVisibility(document.querySelector("#query-loading")); }); Coveo.$$(root).on("queryError", function(e, args) { toggleElementVisibility(document.querySelector("#query-error")); toggleElementVisibility(document.querySelector("#query-loading")); }); Coveo.$$(root).on("querySuccess", function(e, args) { toggleElementVisibility(document.querySelector("#query-loading")); toggleElementVisibility(document.querySelector("#query-done")); }); Coveo.init(root); }); ``` 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: ```html [ ... ] [ ... ]
[ ... ]
``` By default, the 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 doesn't necessarily trigger many complete queries to the Coveo [index](https://docs.coveo.com/en/204/), since the results are already available (and likely still up-to-date) in the 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's 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 part 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 "override" this handler. ```javascript document.addEventListener("DOMContentLoaded", function () { Coveo.SearchEndpoint.configureSampleEndpointV2(); /** * Gets the `enableQueryCache.isEnabled` value if it exists in local storage. * * @returns {boolean|*} The `isEnabled` value if available; `null` otherwise. */ var getEnableQueryCacheValue = function() { return JSON.parse(localStorage.getItem("enableQueryCache")).isEnabled; }; /** * Attaches a handler to the **Disable Query Cache** checkbox so that changing its state also changes the * `enableQueryCache.isEnabled` value in local storage. Automatically selects the checkbox if the * `enableQueryCache.isEnabled` value is currently set to `false`. */ var configureQueryCacheCheckbox = function() { var disableCacheCheckbox = document.querySelector("#disable-query-cache-checkbox"); disableCacheCheckbox.addEventListener("change", function () { localStorage.setItem("enableQueryCache", JSON.stringify({"isEnabled": !this.checked})); }); disableCacheCheckbox.checked = getEnableQueryCacheValue() === false; }; var root = document.querySelector("#search"); Coveo.$$(root).on("afterInitialization", function() { configureQueryCacheCheckbox(); // When instantiating the `queryBuilder`, set the maximum age of cached results according to the // `enableQueryCache.isEnabled` value in local storage. Use the default `maximumAge` parameter value (which is // equivalent to 30 minutes) if `enableQueryCache.isEnabled` is either `true` or undefined. Coveo.$$(root).on("buildingQuery", function(e, args) { args.queryBuilder.maximumAge = getEnableQueryCacheValue() === false ? 0 : null; }); }); Coveo.init(root); }); ``` 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 example), 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 [query syntax](https://docs.coveo.com/en/1552/) allows the end user to enter complex query expressions in the query box. The [`enableQuerySyntax`](https://coveo.github.io/search-ui/components/querybox.html#options.enablequerysyntax) option of your `Searchbox` component lets you enable or disable the use of query syntax in your search page. In certain cases, you might need to disable some of the query syntax features (for example, 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's possible (although not ideal) to modify the `queryBuilder` to artificially achieve this kind of query syntax granularity. > **Note** > > **Query syntax and the JavaScript Search Framework v2.x** > > In v2.x of the Framework, `enableQuerySyntax` defaults to `false`, but it can be overridden by end-user preferences. The following code excerpt shows how you could use a `doneBuildingQuery` event handler to remove certain special characters from the [basic query expression (`q`)](https://docs.coveo.com/en/178/) before sending it to the Coveo Search API. In this example, the `$` character is replaced with the empty string. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("doneBuildingQuery", function(e, args) { args.queryBuilder.expression.parts[0] = args.queryBuilder.expression.parts[0].replace(/\$/g, ""); }); Coveo.init(root); }); ``` ##### Querying commerce catalog content The following code excerpt shows you how to [query your commerce catalog content](https://docs.coveo.com/en/3180/). ```javascript document.addEventListener("DOMContentLoaded", () => { // ... const root = document.getElementById("search"); Coveo.$$(root).on("buildingQuery", (e, args) => { args.queryBuilder.commerce = { catalogId: "" }; }); // ... Coveo.init(root); }); ``` Where you would replace `` with the name of your catalog entity. ##### 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](https://docs.coveo.com/en/200/) value is `User` to uppercase. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("preprocessResults", function(e, args) { args.results.results.forEach(function(result) { if (result.raw && result.raw.objecttype === "User") { result.title = result.title.toUpperCase(); } }); }); Coveo.init(root); }); ``` > **Important** > > 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 frequently find yourself resorting to this kind of result manipulation in your search page, you should probably consider making adjustments in the index (for example, adding or modifying pre- and post-indexing pipeline extensions, field [mapping](https://docs.coveo.com/en/217/) 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](https://docs.coveo.com/en/246/) type present on the current page of results. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("querySuccess", function(e, args) { /** * Removes the `source-type-summary` structure from the search page. */ var cleanUp = function() { var sourceTypeSummary = document.querySelector("#source-type-summary"); if (sourceTypeSummary !== null) { sourceTypeSummary.parentNode.removeChild(sourceTypeSummary); } }; /** * Counts the number of occurrences of each source type on the current page of results. * * @returns {% raw %}{{}}{% endraw %} A key-value set where each key is the name of a source type and each value is its * corresponding number of occurrences on the current page of results. */ var getSourceOccurrences = function() { var sources = {}; for (var i = 0; i < args.results.results.length; i++) { var currentResult = args.results.results[i]; var currentSource = currentResult.raw.source; if (sources[currentSource]) { sources[currentSource] += 1; } else { sources[currentSource] = 1; } } return sources; }; /** * Creates the `source-type-summary` HTML structure, which contains an unordered list of each source type * present on the current page of results and its corresponding number of occurrences. Prepends this node to * the `coveo-results-column` element if it exists, or to the root element of the search interface otherwise. */ var createSourceTypeSummary = function() { var sources = getSourceOccurrences(); if (sources instanceof Object) { var sourceTypeSummary = document.createElement("div"); sourceTypeSummary.setAttribute("id", "source-type-summary"); var sourceTypeSummaryContent = document.createTextNode("Source type summary for this page: "); sourceTypeSummary.appendChild(sourceTypeSummaryContent); var sourceTypeList = document.createElement("ul"); for (var key in sources) { var sourceTypeListItem = document.createElement("li"); var sourceTypeListItemContent = document.createTextNode(" " + key + ": " + sources[key]); sourceTypeListItem.appendChild(sourceTypeListItemContent); sourceTypeList.appendChild(sourceTypeListItem); } sourceTypeSummary.appendChild(sourceTypeList); var resultsColumn = document.querySelector(".coveo-results-column"); if (resultsColumn) { resultsColumn.insertBefore(sourceTypeSummary, resultsColumn.firstChild); } else { root.insertBefore(sourceTypeSummary, root.firstChild); } } }; // Remove the `source-type-summary` element if it already exists in the page to avoid carrying the existing // structure over when displaying another page of results. cleanUp(); createSourceTypeSummary(); }); Coveo.init(root); }); ``` If you run this code sample, you should see the following at the top of your result list: ## Component events _Component_ events are usually triggered by specific components. The following JavaScript Search Framework components have their own sets of events: * `AdvancedSearch` (see [`AdvancedSearchEvents`](https://coveo.github.io/search-ui/classes/advancedsearchevents.html)) * `Analytics` (see [`AnalyticsEvents`](https://coveo.github.io/search-ui/classes/analyticsevents.html)) * `Breadcrumb` (see [`BreadcrumbEvents`](https://coveo.github.io/search-ui/classes/breadcrumbevents.html)) * `CardOverlay` (see [`CardOverlayEvents`](https://coveo.github.io/search-ui/classes/cardoverlayevents.html)) * `FacetSlider` * `Omnibox` * `PreferencesPanel` * `QuerySummary` (see [`QuerySummaryEvents`](https://coveo.github.io/search-ui/classes/querysummaryevents.html)) * `Quickview` * `ResultLayout` * `ResultList` * `SearchAlerts` * `Settings` > **Note** > > 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](https://docs.coveo.com/en/1341/) and [metadata](https://docs.coveo.com/en/218/) of an analytics event to the Coveo Analytics REST [service](https://docs.coveo.com/en/2821/). All `changeAnalyticsCustomData` event handlers receive `ChangeAnalyticsCustomDataEventArgs` as an argument, which extends the [`IChangeableAnalyticsDataObject`](https://coveo.github.io/search-ui/interfaces/ichangeableanalyticsdataobject.html) interface. You can attach handlers to this event to read and modify the information that's about to be sent to the Analytics REST service. ##### Argument object [subs="attributes"]
Name
Description
type The type of event that's 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~anchor id="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 category 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.

You want to include the value of the `product` field for the clicked result in the pushed analytics data: ```javascript Coveo.$$(root).on('changeAnalyticsCustomData', function(e, args) { args.metaObject.product = args.resultData.raw.product; }); ```
### `ResultList` events The `ResultList` component can trigger several events. Two of these events are especially useful: `newResultDisplayed` (singular: "result") and `newResultsDisplayed` (plural: "result**s**"). You can attach handlers to these events to alter the appearance of rendered query results. > **Leading practice** > > **ResultList events versus result templates** > > Usually, you can rely on the [result template evaluation mechanism](https://docs.coveo.com/en/413#about-the-condition-evaluation-mechanism) rather than attaching your own handlers to the `newResultDisplayed` or `newResultsDisplayed` events. #### Event flow The following diagram displays the part of the sequential query event flow where the `ResultList` component triggers the `newResultDisplayed` and `newResultsDisplayed` events. 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. > **Note** > > **A word of caution about this diagram** > > 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. > **Tip** > > **newResultDisplayed versus newResultsDisplayed** > > You can accomplish the exact same thing using either a `newResultDisplayed` or a `newResultsDisplayed` event handler. > However the `newResultDisplayed` event is often slightly easier and cleaner, since it doesn't require writing a loop to iterate through each element in the result list. #### Code sample ##### 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. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("newResultDisplayed", function(e, args) { // Add the source type at the beginning of the result link text. var formattedTitle = args.result.Title = args.result.raw.source + " - " + args.result.Title; args.item.querySelectorAll("div.coveo-result-cell > a.CoveoResultLink").forEach(function(element) { element.innerHTML = formattedTitle }); }); Coveo.init(root); }); ``` #### Handling the `newResultsDisplayed` event All `newResultsDisplayed` 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. #### Code sample ##### Modifying the rendering of each result: The following code excerpt shows how you could use a `newResultsDisplayed` 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. ```javascript document.addEventListener("DOMContentLoaded", function() { Coveo.SearchEndpoint.configureSampleEndpointV2(); root = document.querySelector("#search"); Coveo.$$(root).on("newResultsDisplayed", function(e, args) { // Add the source type at the beginning of the result link text. for (var i = 0; i < e.target.lastChild.children.length; i++) { var currentResult = e.target.lastChild.children[i]; var formattedTitle = currentResult.CoveoResult.raw.source + " - " + currentResult.CoveoResult.Title; currentResult.children[0].querySelectorAll("div.coveo-result-cell > a.CoveoResultLink").forEach(function(element) { element.innerHTML = formattedTitle; }); } }); Coveo.init(root); }); ```