简体   繁体   中英

How to search filter an array of object based on the dynamic value of object key on another array?

So I have a problem while doing the search filtering features for searching through all columns in the Datagrid table; I've implemented the search based on the selected column field, which is working just fine, and there is an option for the search input to search through the All columns .

I get all the column data dynamically from the MUI Grid API and the valueTwo array is the representation of the column data that I got from the MUI Grid API.

const valueOne = [
   {
      name: 'Jacqueline',
      reference: 'PRD-143',
      active: true,
   },
   {
      name: 'Jacqueline',
      reference: 'PRD-143',
      active: true,
   },
   {
      name: 'Jacqueline',
      reference: 'PRD-143',
      active: true,
   }
]
const valueTwo = [
   {
      id: '01',
      field: 'name',
      headerName: 'Name'
   },
   {
      id: '02',
      field: 'reference',
      headerName: 'Reference'
   },
   {
      id: '01',
      field: 'active',
      headerName: 'Status'
   },

]

This is the application, image

This the hooks that I write

export function useSearchTable<T>(
  tableData: T[],
  setTableItems: Dispatch<SetStateAction<T[]>>,
  searchState: string,
) {
  const [selectedColumnHeader, setSelectedColumnHeader] = useState<
    ColumnHeaderInterface | any
  >({
    field: `allColumns`,
    headerName: `All Columns`,
  });
  const [filteredColumnHeaders, setFilteredColumnHeaders] = useState<
    GridStateColDef[] | any
  >();

  const debouncedSearchState = useDebounce(searchState, 500) as string;

  const requestSearch = (dataItems: T[]) => {
    switch (selectedColumnHeader.field) {
      case `allColumns`: {
        let allColumnFilter: T[] = [];
        const columnTempData = [] as any[];

        if (filteredColumnHeaders) {
          for (const columnHeader of filteredColumnHeaders) {
            columnTempData.push(columnHeader.field);
          }
        }

        // TODO: something is broken here
        columnTempData.forEach((columnName) => {
          allColumnFilter = dataItems.filter((itemData: any) => {
            if (
              typeof itemData[columnName] === `boolean` ||
              typeof itemData[columnName] === `number`
            ) {
              String(itemData[columnName])
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            if (typeof itemData[columnName] === `object`) {
              itemData[columnName]?.name
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            return itemData;
          });
        });

        console.log(columnTempData, `itemTempData`);

        console.log(allColumnFilter, `columnFilterSearch`);

        setTableItems(allColumnFilter);

        break;
      }

      default: {
        const filteredSearchData = dataItems.filter((itemData: any) => {
          let data = itemData[selectedColumnHeader.field];

          if (typeof data === `boolean` || typeof data === `number`) {
            data = String(data);
          }

          // TODO: quick fix, but need to research on other API data regarding the resources: vehicles, machines, standalones
          if (typeof data === `object`) {
            data = data?.name;
          }

          console.log(
            data?.toLowerCase().includes(debouncedSearchState.toLowerCase()),
            `data`,
          );

          return data
            ?.toLowerCase()
            .includes(debouncedSearchState.toLowerCase());
        });

        setTableItems(filteredSearchData);

        break;
      }
    }
  };

  useEffect(() => {
    if (tableData) {
      requestSearch(tableData);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [
    debouncedSearchState,
    tableData,
    filteredColumnHeaders,
    selectedColumnHeader,
  ]);

  return {
    setFilteredColumnHeaders,
    setSelectedColumnHeader,
    selectedColumnHeader,
  };
}

columnTempData is basically an array of string containing the field name from the column header data that I set in filteredColumnHeaders . And things that needs to be fix is on the // TODO comment

The code that I expect is to get all the filtered data based on the search through all the columns with the column data that comes from the MUI Grid API.

I'm a one-man engineer and I really need your assistance here:)

I've tried to loop through the column field data and then looping the table list data and access each key based on the column field data, something like this:

        columnTempData.forEach((columnName) => {
          allColumnFilter = dataItems.filter((itemData: any) => {
            if (
              typeof itemData[columnName] === `boolean` ||
              typeof itemData[columnName] === `number`
            ) {
              String(itemData[columnName])
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            if (typeof itemData[columnName] === `object`) {
              itemData[columnName]?.name
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            return itemData;
          });
        });

It should have been returning the all filtered data based on the input given. so no matter what column is being search the data is going to filtered based on the input.

Use map instead of forEach as forEach doesn't return anything

     columnTempData.map((columnName) => {
          allColumnFilter = dataItems.filter((itemData: any) => {
            if (
              typeof itemData[columnName] === `boolean` ||
              typeof itemData[columnName] === `number`
            ) {
              String(itemData[columnName])
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            if (typeof itemData[columnName] === `object`) {
              itemData[columnName]?.name
                .toLowerCase()
                .includes(debouncedSearchState.toLowerCase());
            }

            return itemData;
          });
         return allColumnFilter
        });

I've found the solution, Basically. I was wrong in choosing the right array method for my case.

        allColumnFilter = dataItems.filter((itemData: any) => {
          return columnTempData.find((columnName) => {
            let itemDataTemp = itemData[columnName];

            if (
              typeof itemDataTemp === `boolean` ||
              typeof itemDataTemp === `number`
            ) {
              itemDataTemp = String(itemDataTemp);
            }

            if (typeof itemDataTemp === `object`) {
              itemDataTemp = itemDataTemp?.name;
            }

            return itemDataTemp
              ?.toLowerCase()
              .includes(debouncedSearchState.toLowerCase());
          });
        });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM