Implement a custom component
Implement a custom component
|
|
Note
When possible, create your component in TypeScript. For more information on why it’s considered a good practice, see Create custom components. |
When using the Coveo JavaScript Search Framework, you will sometimes want to add your own custom components (see Create custom components).
In this tutorial, you will be adding a rudimentary custom search box to your page using pure JavaScript. This component will execute a query every time a user selects Enter. It will also have a configurable option to enable search-as-you-type, meaning that a query will be sent every time the user types something when the option is enabled.
Step 1: Create your constructor
First, declare a constructor function that the framework will call to instantiate your custom search box component:
const CustomSearchbox = (function(_super) {
__extends(CustomSearchbox, Coveo.Component);
function CustomSearchbox(element, options, bindings) {
_super.call(this, element, CustomSearchbox.ID, bindings);
this.type = 'CustomSearchBox';
Coveo.Component.bindComponentToElement(element, this);
this.element = element;
this.options = options;
this.bindings = bindings;
}
})(Coveo.Component);
The framework will automatically pass the following arguments when it calls this function:
-
element: the DOM element on which the component is being instantiated. -
options: the options that were passed for the component in the init top-level function call.
|
|
The options argument contains options passed as follows:
It does not contain options passed as |
-
bindings: an object that references different singletons which are used by the framework. This object has the following properties:-
root: the DOM element on which the main SearchInterface component is bound. -
queryStateModel: the State object instance, which can be used to read/write in the state of the search interface. -
queryController: the QueryController object instance, which can be used to execute queries in the search interface. -
searchInterface: the mainSearchInterfacecomponent instance. -
usageAnalytics: the Analytics component instance, which can log various analytics events.
-
Step 2: Add the component ID
In order for your component to work, it needs an ID property that uniquely identifies the component.
This property allows the Coveo JavaScript Search Framework to recognize an element with the CoveoCustomSearchBox class to be instantiated as a component.
Add the following line after the constructor function:
CustomSearchbox.ID = 'CustomSearchbox';
Step 3: Initialize the component
In order for your component to be registered and initialized alongside the Coveo JavaScript Search Framework, call your constructor in the registerAutoCreateComponent function.
Add the following line after the constructor function:
Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox);
Your code should now look like this:
CustomComponent.js
const CustomSearchbox = (function(_super) {
__extends(CustomSearchbox, Coveo.Component);
function CustomSearchbox(element, options, bindings) {
_super.call(this, element, CustomSearchbox.ID, bindings);
this.type = 'CustomSearchBox';
Coveo.Component.bindComponentToElement(element, this);
this.element = element;
this.options = options;
this.bindings = bindings;
}
CustomSearchbox.ID = 'CustomSearchbox';
Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox);
})(Coveo.Component);
|
|
When using the Coveo JavaScript Search Framework 2.x, you can also register your component as a lazy component. This way, your code is only initialized when you have the component on your page (see Lazy versus eager component loading). |
Step 4: Add a function to trigger a query when the Enter key is pressed
As of now, your component is able to be successfully initialized, but it doesn’t do anything.
Since you’re creating a search box, a good function to add would be to trigger a query when the Enter key is selected in the search box.
-
In the constructor, add an event listener on the
keyupevent. Make it so that it calls ahandleKeyUpfunction.this.element.addEventListener('keyup', (e)=> this.handleKeyUp(e)); -
Create the
handleKeyUpfunction. It should only detect if the released key was Enter, and call theexecuteNewQueryfunction when it is.CustomSearchbox.prototype.handleKeyUp = function(e) { if (e.key == 'Enter') { this.executeNewQuery(); } } -
Create the
executeNewQueryfunction. The function should read the value entered in your component, and set it as the new query.CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.queryController.executeQuery(); } -
In the
executeNewQueryfunction, send a Usage Analytics event when the query is performed. This is so you can track what your users search (see Why You Should Add Usage Analytics Events).CustomSearchbox.prototype.executeNewQuery = function() { this.bindings.queryStateModel.set('q', this.element.value); this.bindings.usageAnalytics.logSearchEvent({ name : 'submitSearchbox', type : 'CustomSearchbox' }); this.bindings.queryController.executeQuery(); }
Your code should now look like this:
const CustomSearchbox = (function(_super) {
__extends(CustomSearchbox, Coveo.Component);
function CustomSearchbox(element, options, bindings) {
_super.call(this, element, CustomSearchbox.ID, bindings);
this.type = 'CustomSearchBox';
Coveo.Component.bindComponentToElement(element, this);
this.element = element;
this.options = options;
this.bindings = bindings;
this.element.addEventListener('keyup', (e) => this.handleKeyUp(e));
}
CustomSearchbox.prototype.handleKeyUp = function(e) {
if (e.key == 'Enter') {
this.executeNewQuery();
}
}
CustomSearchbox.prototype.executeNewQuery = function() {
this.bindings.queryStateModel.set('q', this.element.value);
this.bindings.usageAnalytics.logSearchEvent({
name: 'submitSearchbox',
type: 'CustomSearchbox'
});
this.bindings.queryController.executeQuery();
}
CustomSearchbox.ID = 'CustomSearchbox';
Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox);
})(Coveo.Component);
|
|
Note
To get consistent data and reporting inside Coveo Analytics, it’s mandatory that every search event be logged to the service. Otherwise, the framework will log a warning every time a query is submitted without first having logged a search event. If you don’t log any search events when you trigger a query, in the your browser console, you will most probably see a warning like this one:
In a Google Chrome browser, the warning looks like this:
|
Step 5: Add a search-as-you-type option
You can add options to your custom component.
Those options can be modified using the data- HTML attribute (see ComponentOptions).
A nice option to have on a search box is the search-as-you-type function, which triggers a query while the user is typing, allowing them to preview the results while typing their query.
|
|
Note
The |
-
In the constructor, change the
this.options = optionsline to initialize your other options (see ComponentOptions - initComponentOptions).this.options = Coveo.ComponentOptions.initComponentOptions(element, CustomSearchbox, options); -
Declare a
searchAsYouTypeoption on your component. You want this option to be a Boolean (see ComponentOptions - buildBooleanOption). For this example, you can make its default valuefalse.CustomSearchbox.options = { searchAsYouType : Coveo.ComponentOptions.buildBooleanOption({defaultValue: false}) } -
Change your
handleKeyUpfunction so that, whensearchAsYouTypeis enabled, a query is performed every time a key is released instead of only when theEnterkey is.CustomSearchbox.prototype.handleKeyUp = function(e) { if (this.options.searchAsYouType) { this.executeNewQuery(); } else if (e.key == 'Enter') { this.executeNewQuery(); } }
Your code should now look like this:
const CustomSearchbox = (function(_super) {
__extends(CustomSearchbox, Coveo.Component);
function CustomSearchbox(element, options, bindings) {
_super.call(this, element, CustomSearchbox.ID, bindings);
this.type = 'CustomSearchBox';
Coveo.Component.bindComponentToElement(element, this);
this.element = element;
this.options = Coveo.ComponentOptions.initComponentOptions(element, CustomSearchbox, options);
this.bindings = bindings;
this.element.addEventListener('keyup', (e) => this.handleKeyUp(e));
}
CustomSearchbox.prototype.handleKeyUp = function(e) {
if (this.options.searchAsYouType) {
this.executeNewQuery();
} else if (e.key == 'Enter') {
this.executeNewQuery();
}
}
CustomSearchbox.prototype.executeNewQuery = function() {
this.bindings.queryStateModel.set('q', this.element.value);
this.bindings.usageAnalytics.logSearchEvent({
name : 'submitSearchbox',
type : 'CustomSearchbox'
});
this.bindings.queryController.executeQuery();
}
CustomSearchbox.options = {
searchAsYouType : Coveo.ComponentOptions.buildBooleanOption({defaultValue: false})
}
CustomSearchbox.ID = 'CustomSearchbox';
Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox);
})(Coveo.Component);
You can now add data-search-as-you-type='true' to your CoveoCustomSearchbox element to enable your option.
<input class="CoveoCustomSearchbox" data-search-as-you-type='true'></input>
Step 6: Add the newly created component in a search page
Now that you have completed your rudimentary custom search box, you’re ready to add it to your page:
</head>
<script>
// You could of course instead insert a script resource in the header of your search page.
const CustomSearchbox = (function(_super) {
__extends(CustomSearchbox, Coveo.Component);
function CustomSearchbox(element, options, bindings) {
_super.call(this, element, CustomSearchbox.ID, bindings);
this.type = 'CustomSearchBox';
Coveo.Component.bindComponentToElement(element, this);
this.element = element;
this.options = Coveo.ComponentOptions.initComponentOptions(element, CustomSearchbox, options);
this.bindings = bindings;
this.element.addEventListener('keyup', (e) => this.handleKeyUp(e));
}
CustomSearchbox.prototype.handleKeyUp = function(e) {
if (this.options.searchAsYouType) {
this.executeNewQuery();
} else if (e.key == 'Enter') {
this.executeNewQuery();
}
}
CustomSearchbox.prototype.executeNewQuery = function() {
this.bindings.queryStateModel.set('q', this.element.value);
this.bindings.usageAnalytics.logSearchEvent({
name: 'submitSearchbox',
type: 'CustomSearchbox'
});
this.bindings.queryController.executeQuery();
}
CustomSearchbox.options = {
searchAsYouType: Coveo.ComponentOptions.buildBooleanOption({ defaultValue: false })
}
CustomSearchbox.ID = 'CustomSearchbox';
Coveo.Initialization.registerAutoCreateComponent(CustomSearchbox);
})(Coveo.Component);
</script>
[...]
<!-- The class CoveoCustomSearchbox corresponds to the ID of the component -->
<body class='CoveoSearchInterface'>
<input class='CoveoCustomSearchbox' data-search-as-you-type='true'></input>
</body>