Search code examples
reactjstypescriptkendo-react-ui

KendoReact Grid filter and sort does not work after grouping data


After grouping data, the KendoReact Grid filter and sort functions do not work.

Interestingly, if I skip the data grouping step and simply present the ungrouped data, the filter and sort functions work flawlessly.

My goal is to find a solution that enables me to filter and sort grouped data within the KendoReact Grid effectively. Despite extensive searches on the KendoReact website and documentation, I haven't been able to find any relevant source code examples or documentation that address this particular issue.

The Customer.tsx component file returns the grid component.

import { filterBy, groupBy, process } from "@progress/kendo-data-query";
import { Grid, GridColumn, getSelectedState } from "@progress/kendo-react-grid";
import { useCallback, useState } from "react";
import { ColumnMenu } from "./ColumnMenu";
import { setExpandedState, setGroupIds, setSelectedState } from "@progress/kendo-react-data-tools";

const customers = [
    { Id: 1, Name: "data1", Family: "Pack", MobileNumber: "0223366554" },
    { Id: 2, Name: "data2", Family: "Pack", MobileNumber: "0223366554" },
    { Id: 3, Name: "data", Family: "Mi", MobileNumber: "0223366554" },
    { Id: 4, Name: "data", Family: "Help", MobileNumber: "0223366554" },
    { Id: 5, Name: "test", Family: "Friend", MobileNumber: "0223366554" },
    { Id: 6, Name: "test", Family: "Friend", MobileNumber: "0223366554" },
];

const DATA_ITEM_KEY = "Id";
const SELECTED_FIELD = "selected";

const initialGroup: any[] | (() => any[]) = [];
const processWithGroups = (data: any, group: any) => {
    const newDataState = groupBy(data, group);
    setGroupIds({
        data: newDataState,
        group: group,
    });
    return newDataState;
};

const initialState: any = {
    take: 20,
    skip: 0
}

const Customer = () => {
    const [dataState, setDataState] = useState(initialState);
    const [customerSelectedState, setCustomerSelectedState] = useState<any>({});
    const [group, setGroup] = useState(initialGroup);
    
    const [resultState, setResultState] = useState(
        processWithGroups(customers, initialGroup)
    );
    const [collapsedState, setCollapsedState] = useState([]);
    const onGroupChange = useCallback((event: any) => {
        const newDataState = processWithGroups(customers, event.group);
        setGroup(event.group);
        setResultState(newDataState);
    }, []);
    const onExpandChange = useCallback(
        (event: any) => {
        const item = event.dataItem;
        if (item.groupId) {
            const newCollapsedIds: any = !event.value
            ? [...collapsedState, item.groupId]
            : collapsedState.filter((groupId) => groupId !== item.groupId);
            setCollapsedState(newCollapsedIds);
        }
        },
        [collapsedState]
    );

    const onSelectionChange = (event: any) => {
        const newSelectedState = getSelectedState({
            event,
            selectedState: customerSelectedState,
            dataItemKey: DATA_ITEM_KEY,
        });
        setCustomerSelectedState(newSelectedState);
    };

    const onDataStateChange = useCallback(
        (event: any) => {
            setDataState(event.dataState);
        }, [dataState]);

    const expandeedData = setExpandedState({
        data: resultState,
        collapsedIds: collapsedState,
    });

    const selectedData = setSelectedState({
        data: expandeedData,
        selectedState: customerSelectedState,
        dataItemKey: DATA_ITEM_KEY,
        selectedField: SELECTED_FIELD
    });

    const result = process(selectedData, dataState);

    return (
        <Grid dataItemKey={DATA_ITEM_KEY}
              data={result}
              {...dataState}
              selectedField={SELECTED_FIELD}
              selectable={{
                enabled: true,
                drag: false,
                cell: false,
                mode: "single",
              }}
              sortable={true}
              onGroupChange={onGroupChange}
              group={group}
              onExpandChange={onExpandChange}
              expandField="expanded"
              onSelectionChange={onSelectionChange}
              onDataStateChange={onDataStateChange}
              >
            <GridColumn title="Id" field="Id" width="300" columnMenu={ColumnMenu}/>
            <GridColumn title="Name" field="Name" width="300" columnMenu={ColumnMenu}/>
            <GridColumn title="Family" field="Family" width="300" columnMenu={ColumnMenu}/>
            <GridColumn title="Mobile Number" field="MobileNumber" width="300" columnMenu={ColumnMenu}/>
        </Grid>
    );
}

export default Customer;

The ColumnMenu.tsx component file returns a column menu, including features like filtering and sorting.

import { GridColumnMenuSort, GridColumnMenuFilter, GridColumnMenuGroup } from '@progress/kendo-react-grid';
export const ColumnMenu = (props: any) => {
  return <div>
        <GridColumnMenuSort {...props} />
        <GridColumnMenuFilter {...props} />
        <GridColumnMenuGroup {...props} />
      </div>;
};

I know result = process(selectedData, dataState) doesn't work correctly. so, what should I do?


Solution

  • After searching for and testing solutions, I found this link related to my problem, and I was able to solve my problem with it.