How to Integrate SmartHub with the React Framework
SmartHub contains several APIs and UI components that ca be reused to build your own search center using any framework you choose.
In this example you can see how to setup SmartHub UI to work together with React components and how to integrate your UI components in SmartHub pages
How to Embed React into SmartHub Pages
To enable SmartHub pages to load React components you need to:
- Pause the initialization of SmartHub once the authentication is complete and before the UI initialization starts
- Run the React rendering so that any SmartHub components that you embedded inside React components exist in the DOM prior to SmartHub UI initialization
- Resume the SmartHub UI initialization step
To do so you will have to add an event listener for the "SHPreInit" event and use the skip property to tell SmartHub to pause the UI initialization
document.body.addEventListener("SHPreInit", function(ev){
//Skip the current initialization to run it after React render
ev.detail[2].skip = true;
});
Inside the same event handler you want to start React initialization by calling ReactDOM.render
var root = document.querySelector("#ReactRoot");
document.body.addEventListener("SHPreInit", function(ev){
//Skip the current initialization to run it after React render
ev.detail[2].skip = true;
ReactDOM.render(<App />, root);
});
Once the ReactDOM rendering is complete you need to resume the SmartHub initialization - you do this by calling window.SH.initUI as the callback for ReactDOM.render
var root = document.querySelector("#ReactRoot");
document.body.addEventListener("SHPreInit", function(ev){
//Skip the current initialization to run it after React render
ev.detail[2].skip = true;
ReactDOM.render(<App />, root, function(){
window.SH.initUI();
});
});
Example: You can see an example of this functionality by navigating to the /themes/React/source folder under your SmartHub installation directory.
The file index.js from the src sub-directory shows a working example of embedding a React App inside a SmartHub page
How to Embed SmartHub Components into React Components
Because SmartHub components are normal DOM elements with special classes and attributes, there are no special steps needed to embed SmartHub components into React components.
The only limitation is that all the SmartHub components needs to exist in the DOM prior to the UI initialization.
Below is an example of a React component that replicates the SmartHub Results page header - which will contain the logo, the SmartHub Searchbox component and the Share & Export to Excel functionality
import React from 'react';
const ResultsSearchHeader = () => {
return (
<div class="sh-row-header sh-header-grid">
<div class="sh-header-top sh-column-left">
<a href="/">
<img class="logo" src="/image/logo.png" />
</a>
</div>
<div class="coveo-search-section sh-header-top sh-column-middle">
<div class="CoveoSearchbox" data-placeholder="Search..." data-add-scoped-search="true" data-show-keep-refiners="true"></div>
</div>
<div class="sh-header-top ribbon-container sh-column-right"></div>
<div class="sh-header-bottom sh-column-left"></div>
<div class="sh-header-bottom sh-column-middle">
<div id="menu"></div>
<div class="CoveoSettings" data-caption="Tools" data-show-icon="false">
<div class="CoveoShareQuery"></div>
<div class="CoveoExportToExcel" data-number-of-results="500" data-batch-size="500" data-template-path="~/Templates/ExportToExcelTemplate.xlsx" data-start-cell="A1" data-property-mappings="title,Title;author,Author;excerpt,Summary;filetype,Result Type;date,Last Modified Time;ContentSource,Content Source;clickUri,Document Path;Size,File Size(in bytes)">
</div>
</div>
</div>
<div class="sh-header-bottom sh-column-right"></div>
</div>
);
};
export default ResultsSearchHeader;
How to Embed SmartHub Display Templates into React Components
SmartHub display templates are implemented as <script> tags that have type "text/underscore". Because of this, the React component that wraps the SmartHub display template needs to rely on the dangerouslySetInnerHTML capability of the Framework
Below is an example on how the default Display template would be wrapped as a React component
import React from 'react';
const ResultsDisplayTemplate = () => {
function createDisplayTemplate() {
return { __html: '<div class="coveo-result-frame core-result">' +
'<div class="CoveoOpenPreviewAction"></div>' +
'<div class="core-result-info-wrapper">' +
'<div class="core-result-info">' +
'<div class="core-info" >' +
'<a class="CoveoResultLink" rel="noreferrer" data-always-open-in-new-window="true"></a>' +
'</div>' +
'<div class="core-info" >' +
'<div class="CoveoFieldValue result-summary" data-field="@excerpt" data-caption="Excerpt" data-html-value="true"></div>' +
'</div>' +
'<div class="core-info widgets-placeholder" ></div>' +
'</div>' +
'<div class="CoveoActionBar core-action-bar" >' +
'<a class="CoveoResultLink prettyURL sh-float-left" rel="noreferrer" target="_blank">' +
'<span title="<%= (raw.filetype||\'document\') + " from " + (raw.contentsource || raw.clickUri || \'Source\') %>"><%= (SH.utils.getSourceSystemImage(raw.clickUri, raw.ContentSource) || raw.ContentSource) %></span>' +
'<span title="<%= raw.clickUri %>"><%= SH.utils.prettifyURL(raw.clickUri) %></span>' +
'</a>' +
'<div class="sh-float-right">' +
'<div class="ReactResultsButton"></div>' +
'</div>' +
'<div class="open-preview-button hidden sh-float-right">' +
'<i class="sh-icon-button far fa-eye"></i>' +
'<span>Preview</span>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
}
}
return (
<script type='text/underscore' class='result-template' data-condition='isUserProfile != "true"' dangerouslySetInnerHTML={createDisplayTemplate()} /> );
};
export default ResultsDisplayTemplate;
How to Embed React Components into SmartHub Display Templates
Because SmartHub display templates are static scripts in the DOM, for React components to be embedded into them you need to rely on the newResultDisplayed event to inject React components into the display template of each result
To do so, you need to:
- Add a place-holder in the display template
- Attach to the event triggered when the results are displayed
- In the event handler:
- read the result properties from the event details
- find the place-holder from the display template where you want the React component injected
- render the React component into the place-holder
For example, let's assume you have the following React component - an anchor that opens a URL in a new tab:
import React from 'react';
const ResultsButton = (props) => {
return (
<a target="_blank" href={props.url}>Open</a> );
};
export default ResultsButton;
And then you modify the display template and add a DIV tag with the class "ReactResultButton".
To inject the React link component in each result that is being displayed by SmartHub at search time, you would run the following snippet:
document.body.addEventListener("newResultDisplayed", function(e){
var result = e.detail.result;
var btn = document.querySelector(".ReactResultsButton");
ReactDOM.render(React.createElement(ResultsButton, { url: result.clickUri }), btn);
});
Example of React and SmartHub integration
For a working example that showcases all the use-cases above please navigate to your https://<smarthubaddress>/themes/React page.
The source code for this can be found in your SmartHub installation directory under /themes/React/source.
The sample application is built using NodeJS v12 and React version greater than 16.8.3.
To make changes to the code and test them out you need to use your favorite editor to make the changes and then:
- start a Command Prompt instance as an Administrator
- navigate to the themes/React/sources directory
- run the command:
npm run build
- copy the contents of the newly generate "build" folder directly under the /themes/React/ folder
- usually the contents would be a file named index.html and a folder named static
Refresh your browser to see the outcome of your changes