The Redwood Smart Search component offers a robust solution for end-users to construct intricate queries on various data sets. Building upon our previous blog, where we demonstrated its usage with a listView based on VB's business objects or Fusion Apps service, this article explores its versatility in creating complex queries for other data sources and filtering data in different UI components.
In the video below, we present an example of a page that retrieves data from an ORDS REST service and displays it in a table. By incorporating the Smart Search, we enable users to define filters for the data set, relying on ORDS to do the query in the database.
The Smart Search component stores the user-defined query criteria in a page variable. We attach an action chain to this variable's value change event. Within this chain, we parse the criteria and construct the corresponding query for the ORDS service, ensuring it returns the filtered data as expected.
To streamline the process, we utilize a transform function to convert the query syntax from the standard SDP filterCriterion structure to the format required by ORDS. Alternatively, developers can opt to parse the Smart Search criteria into a query parameter, which can then be passed to the ORDS or any other REST endpoint. (We covered how to work with ORDS and provided an example of transform function in this blog)
Here is a video showing the creation of the smart search page and explaining the action chain and the values returned from the smart search:
The basic steps are:
- Defined variables for the filterCriterion and searchConfiguration (special type)
- Add the search configuration json file to your project
- Add event listener action chain
Sample code for the action chain – (feel free to change and optimize as needed):
define([
'vb/action/actionChain',
'vb/action/actions',
'vb/action/actionUtils',
], (
ActionChain,
Actions,
ActionUtils
) => {
'use strict';
class filterCriterionListener extends ActionChain {
/**
* @param {Object} context
* @param {Object} params
* @param {{oldValue:any,value:any}} params.event
*/
async run(context, { event }) {
const { $page, $flow, $application, $constants, $variables } = context;
let myFilter2 = [];
// Check if there is a condition
if (event.value) {
// If there is only one condition
if (event.value.$tag != "_root_") {
myFilter2 = await this.parseCondition(context, { event: event });
} else {
// For multiple conditions
const results = await ActionUtils.forEach(event.value.criteria, async (item, index) => {
let aFilter2 = undefined;
let condition2 = "";
if (item.$tag === "idFilter") {
const results3 = await ActionUtils.forEach(item.criteria, async (item, index) => {
aFilter2 = { "attribute": "id", "op": item.op, "value": item.value.id };
myFilter2.push(aFilter2);
}, { mode: 'serial' });
} else {
if (item.$tag === "$keyword$") {
aFilter2 = { "attribute": "department", "op": "$co", "value": item.text };
myFilter2.push(aFilter2);
}
}
}, { mode: 'serial' });
}
}
$variables.getDepartmentsListSDP.filterCriterion = {
op: '$and',
criteria: myFilter2
};
await Actions.fireDataProviderEvent(context, {
target: $variables.getDepartmentsListSDP,
refresh: null,
});
}
/**
* @param {Object} context
* @param {Object} params
* @param {any} params.event
* @return {object[]}
*/
async parseCondition(context, { event }) {
const { $page, $flow, $application, $constants, $variables, $tag, $keyword, $co } = context;
let myFilter = [];
let aFilter = undefined;
let condition = "";
if (event.value.$tag === "idFilter") {
const results2 = await ActionUtils.forEach(event.value.criteria, async (item, index) => {
aFilter = { "attribute": "id", "op": item.op, "value": item.value.id };
myFilter.push(aFilter);
}, { mode: 'serial' });
} else {
if (event.value.$tag === "$keyword$") {
aFilter = { "attribute": "department", "op": "$co", "value": event.value.text };
myFilter.push(aFilter);
}
}
return myFilter;
}
}
return filterCriterionListener;
});
