Is it possible to make a global Search Feature?

How can I make a global search feature that allows my users to search for information from the data sources?

For example, I want my users to be able to easily be able to search through event names, articles, and people. All of this information is housed in different data sources. But having a central location for my users to search for all of these topics instead of going to several different lists would be ideal.

HTML section:
Add a class with any name to the LFD, that should have global search functionality. In my case, it’s a class=“global_search”

Screen JS section:
First of all, we need to create a variable with a list of data sources and columns in each data source for the global search. So ‘globalSearchColumns’ variable is an array of 3 objects. Each object has:

1. Required key-value pairs:

  • DS - the name of the ds for the global search
  • Columns - an array of columns in this ds to filter by
  • Column names must be unique for the entire global search. For example, if you want to have a global search across two data sources, in each of which you want to be able to search by a column with a name ‘Title’, then in one of the data sources the column ‘Title’ should be renamed.

2. Optional key-value pairs:

  • Query - additional query to filter the data. Use this if you don’t want to return all the records from the ds. In our case the user should only see the posts from ‘Posts’ ds with ‘State’ equal to ‘Approved’ and ‘Status’ equal to ‘Published’

The code below should be pasted in JS section of your screen with a global search
Update it to match your data source names, columns and queries (optional)

let globalSearchColumns = [
  {
    DS: "Posts",
    Columns: ["Title of Post", "Share Content"],
    Query: {
      where: {
        State: "Approved",
        Status: "Published",
      }
    }
  },
  {
    DS: "Users",
    Columns: ["firstName", "lastName"]
  },
  {
    DS: "Groups",
    Columns: ["Name", "Description"]
  }
];

Next we need to create queries based on our globalSearchColumns variable
In the code below you should only update the class name from HTML, so use your own class name on line 3 instead of ‘.global_search’

Fliplet.Hooks.on("flListDataBeforeGetData", function (options) {
  //use your class name to initialise global search on the specific LFD
  if ($(options.container[0]).closest(".global_search").length) {
    let promises = [];
    //create list of promises
    _.forEach(globalSearchColumns, function (seachItem) {
      if (seachItem.Query) {
        let query = {
          ...seachItem.Query,
          attributes: seachItem.Columns,
        };

        promises.push(
          Fliplet.DataSources.connectByName(seachItem.DS).then(function (
            connection
          ) {
            return connection.find(query);
          })
        );
      } else {
        promises.push(
          Fliplet.DataSources.connectByName(seachItem.DS).then(function (
            connection
          ) {
            return connection.find({ attributes: seachItem.Columns });
          })
        );
      }
    });
    //run all the promises to get all the data for the global search
    return Promise.all(promises).then(function (allData) {
      return (options.config.getData = function () {
        allSearchData = _.flatten([...allData]);
        let columns = _.flatMap(globalSearchColumns, "Columns");
        _.forEach(allSearchData, function (record) {
          let recordKeys = Object.keys(record.data);
          _.forEach(globalSearchColumns, function (globalSearchItem) {
            const intersectionResult = _.intersection(
              recordKeys,
              globalSearchItem.Columns
            );
            if (intersectionResult.length > 0) {
              record.data.dsName = globalSearchItem.DS;
              return false;
            }
          });
        });
        return Promise.resolve((options.records = allSearchData));
      });
    });
  }
});

LFD settings:
1. No need to specify any ds
2. Number of list items to show = 0
3. Enable LFD search by all columns specified in globalSearchColumns variable. You can simply copy paste column names
4. You might need to update component’s HTML to show the found data. Go to LFD settings → Edit component’s code → I want to edit the HTML template → List template → paste the code bellow

Paste this code to the HTML of LFD and update it to match your column names

DS: {{originalData.[dsName]}}.
    {{#ifCond originalData.[Title of Post] '||' originalData.[Share Content]}}
    Post: {{#if originalData.[Title of Post]}}{{originalData.[Title of Post]}}{{/if}} 
          {{#if originalData.[Share Content]}}{{originalData.[Share Content]}}{{/if}}
    {{/ifCond}}

    {{#ifCond originalData.[firstName] '||' originalData.[lastName]}}
    User: {{#if originalData.[firstName]}}{{originalData.[firstName]}}{{/if}} 
          {{#if originalData.[lastName]}}{{originalData.[lastName]}}{{/if}}
    {{/ifCond}}

    {{#ifCond originalData.[Name] '||' originalData.[Description]}}
    Group: {{#if originalData.[Name]}}{{originalData.[Name]}}{{/if}} 
           {{#if originalData.[Description]}}{{originalData.[Description]}}{{/if}}
    {{/ifCond}}

The first line of code will show you the name of the data source, the search result records are taken from
The next 3 lines of code (between {{#ifCond}} and {{/ifCond}}) should be duplicated as many time as number of data sources you have specified in the globalSearchColumns variable.
The code should be updated with the corresponding column names. For example, if you have a ds to be searched by 3 column (Name, Surname, Address), you would need to update the condition to look like this:

{{#ifCond originalData.[Name] '||' originalData.[Surname]}}
    Data: {{#if originalData.[Name]}}{{originalData.[Name]}}{{/if}} 
          {{#if originalData.[Surname]}}{{originalData.[Surname]}}{{/if}} 
          {{#if originalData.[Address]}}{{originalData.[Address]}}{{/if}}
{{/ifCond}}

There is no need to use triple or more complex conditions. It is enough to use a double condition with the names of the columns that are most likely to be filled in the data source, but inside the condition you can show as many columns as you want, while wrapping the output of each column in its own condition.
You can also replace the double condition with a single one. For example, if the search is carried out by the name of a column that is required to be filled out.

{{#if originalData.[Name]}}
    Data: {{#if originalData.[Name]}}{{originalData.[Name]}}{{/if}} 
          {{#if originalData.[Surname]}}{{originalData.[Surname]}}{{/if}} 
          {{#if originalData.[Address]}}{{originalData.[Address]}}{{/if}}
{{/if}}

Search result will look like this:

image