skip to Main Content

I want to build a search function which can result in returning the search response in deeply nested hierarchy.

Type of data I am having::

[
  {
    label: "Navigation",
    accordion: true,
    key: "navigation",
    actions: [
      {
        action: "navigateTo",
        label: "Navigate To"
      },
      {
        action: "Back",
        label: "Back"
      },
      {
        action: "closeDialog",
        label: "Close Dialog"
      },
      {
        action: "delay",
        label: "Delay"
      }
    ]
  }]

and I am searching "Delay" it will returns the following result.

[
  {
    label: "Navigation",
    accordion: true,
    key: "navigation",
    actions: [
      {
        action: "delay",
        label: "Delay"
      }
    ]
  }]

If I am searching "navigation" this is expected to return the complete object with a "navigation" label.

[
  {
    label: "Navigation",
    accordion: true,
    key: "navigation",
    actions: [
      {
        action: "navigateTo",
        label: "Navigate To"
      },
      {
        action: "Back",
        label: "Back"
      },
      {
        action: "closeDialog",
        label: "Close Dialog"
      },
      {
        action: "delay",
        label: "Delay"
      }
    ]
  }]

I need help building a search function which can be able to search the results on the basis of labels in the nested deep hierarchy. Here I want to perform a search on the basis of the "label" field. And will always return the result with its parent-wrapped object.
Here you can check the sample I have created:: https://codesandbox.io/s/bold-chihiro-4uv3dz?file=/src/App.js

2

Answers


  1. You can write the search function like this:

        function search(data, keyword) {
        // Return the complete data or null if data does not exist in case of our search keyword is empty
        if (keyword && keyword === "") {
            return data ?? null;
        }
        //Return searched result if search keyword is not empty
        let result = data && data.reduce((acc, value) => {
            let item = null;
            if (value["label"].toLowerCase().indexOf(keyword.toLowerCase()) !== -1) {
                item = value;
            } else {
                if (value["actions"]) {
                    let actions = search(value["actions"], keyword); // call recursive function
                    item = { ...value, actions };
                }
            }
            //push the item in acc(accumulator) if it is not null
            if (item) {
                acc.push(item);
            }
            return acc;
        }, []);
        let searchResult = result.filter((item) => {
            return item["actions"]?.length < 1 ? false : true;
        });
        return searchResult;
    }
        let result = search(data, "Create");
    

    Here is the working example:

    https://codesandbox.io/embed/upbeat-tharp-if17ff?fontsize=14&hidenavigation=1&theme=dark

    By the way now the search is case sensitive, you can change the indexOf with your desired text camparison.

    Login or Signup to reply.
  2. Here i have created this in plain JS. You can modify it according to your taste.

    const data = [{
        label: "Navigation",
        accordion: true,
        key: "navigation",
        actions: [{
            action: "navigateTo",
            label: "Navigate To"
          },
          {
            action: "Back",
            label: "Back"
          },
          {
            action: "closeDialog",
            label: "Close Dialog"
          },
          {
            action: "delay",
            label: "Delay"
          }
        ]
      },
      {
        label: "Backend/Database",
        key: "db",
        accordion: true,
        actions: [{
            label: "Firestore",
            accordion: true,
            key: "fsb",
            actions: [{
                label: "Create document",
                action: "fsCreateDoc"
              },
              {
                label: "Update document",
                action: "fsUpdateDoc"
              },
              {
                label: "Delete document",
                action: "fsDeleteDoc"
              }
            ]
          },
          {
            label: "API request",
            action: "api"
          },
          {
            label: "Firebase authentication",
            accordion: true,
            key: "fsbAuth",
            actions: [{
                label: "Firebase login",
                action: "fsbLogin"
              },
              {
                label: "Create account",
                action: "fsbCreateAccount"
              },
              {
                label: "Phone sign-in",
                action: "fsbPhoneLogin"
              },
              {
                label: "Logout",
                action: "fsbLogout"
              },
              {
                label: "Reset password",
                action: "fsbResetPw"
              },
              {
                label: "Verify SMS code",
                action: "fsbVerifySMSCode"
              },
              {
                label: "Send email verification link",
                action: "fsbSendEmailVeriLink"
              },
              {
                label: "Delete user",
                action: "fsbDeleteUser"
              }
            ]
          }
        ]
      }
    ];
    
    const resultContainer = document.querySelector('#result');
    let searchWord = "Navigation";
    
    function start() {
      searchWord = document.querySelector('#searchField').value;
    
      let final = [];
      if (searchWord) {
        for (let elem of data) {
          const res = searchMe(elem);
          if (res) {
            final.push({...res});
          }
        }
      }
    
      if (final.length) {
        resultContainer.innerHTML = '<pre>' + JSON.stringify(final, null, 2) + '</pre>';
      } else {
        resultContainer.innerHTML = "";
      }
    }
    
    function searchMe(elem) {
      if (elem.label.toLowerCase().indexOf(searchWord.toLowerCase()) >= 0) {
        return elem;
      }
    
      if (elem.actions && elem.actions.length) {
        const newActions = [];
        for (let action of elem.actions) {
          const res = searchMe(action);
          if (res) {
            newActions.push(res);
          }
        }
    
        if (newActions.length) {
          return {
            ...elem,
            actions: newActions
          };
        }
      }
    
      return null;
    }
    <input type="text" placeholder="keyword" id="searchField" onkeyup="start()" />
    <div id="result"></div>

    codesandbox React: https://codesandbox.io/s/withered-glitter-njg0mn

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search