Skip to content

Commit

Permalink
feat: work in selecting all rows
Browse files Browse the repository at this point in the history
  • Loading branch information
mguellsegarra committed Sep 20, 2024
1 parent d69e0a5 commit 7647bfb
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 73 deletions.
20 changes: 8 additions & 12 deletions src/components/InfiniteTable/HeaderCheckbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,27 +52,20 @@ export const HeaderCheckbox = memo(
({
selectedRowKeysLength,
totalRows,
allRowSelected,
onHeaderCheckboxChange,
allRowSelectedMode,
onSelectionCheckboxClicked,
}: {
selectedRowKeysLength: number;
totalRows: number;
allRowSelected: boolean;
onHeaderCheckboxChange: (value: boolean | null) => void;
allRowSelectedMode: boolean;
onSelectionCheckboxClicked?: () => void;
}) => {
const noRowsSelected = selectedRowKeysLength === 0;
const someRowsSelected =
selectedRowKeysLength > 0 && totalRows !== selectedRowKeysLength;
const allRowSelected = selectedRowKeysLength === totalRows && totalRows > 0;

let value: boolean | null = false;

if (allRowSelectedMode) {
value = true;
} else if (totalRows === selectedRowKeysLength && totalRows > 0) {
value = true;
} else if (allRowSelected) {
if (allRowSelected) {
value = true;
} else if (noRowsSelected) {
value = false;
Expand All @@ -81,7 +74,10 @@ export const HeaderCheckbox = memo(
}

return (
<HeaderCheckboxComp value={value} onChange={onHeaderCheckboxChange} />
<HeaderCheckboxComp
value={value}
onChange={onSelectionCheckboxClicked!}
/>
);
},
);
Expand Down
105 changes: 46 additions & 59 deletions src/components/InfiniteTable/InfiniteTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
memo,
ReactNode,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useRef,
Expand All @@ -24,10 +23,10 @@ import {
import { TableProps } from "@/types";
import { useDeepArrayMemo } from "@/hooks/useDeepArrayMemo";
import { HeaderCheckbox } from "./HeaderCheckbox";
import { useRowSelection } from "./useRowSelection";
import { areStatesEqual, useColumnState } from "./useColumnState";
import { CHECKBOX_COLUMN, STATUS_COLUMN } from "./columnStateHelper";
import debounce from "lodash/debounce";
import { useWhyDidYouRender } from "@/hooks/useWhyDidYouRender";

const DEBOUNCE_TIME = 100;
const DEFAULT_TOTAL_ROWS_VALUE = Number.MAX_SAFE_INTEGER;
Expand All @@ -53,7 +52,7 @@ export type InfiniteTableProps = Omit<
onGetSelectedRowKeys?: () => any[] | undefined;
totalRows?: number;
allRowSelectedMode?: boolean;
onAllRowSelectedModeChange?: (allRowSelectedMode: boolean) => void;
onSelectionCheckboxClicked?: () => void;
footer?: ReactNode;
footerHeight?: number;
hasStatusColumn?: boolean;
Expand All @@ -62,6 +61,7 @@ export type InfiniteTableProps = Omit<
};

export type InfiniteTableRef = {
setSelectedRows: (keys: number[]) => void;
unselectAll: () => void;
refresh: () => void;
};
Expand All @@ -81,8 +81,7 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
onGetFirstVisibleRowIndex,
onGetSelectedRowKeys,
totalRows = DEFAULT_TOTAL_ROWS_VALUE,
onAllRowSelectedModeChange,
allRowSelectedMode: allRowSelectedModeProps,
onSelectionCheckboxClicked,
footer,
footerHeight = 50,
onRowStatus,
Expand All @@ -93,40 +92,28 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
const gridRef = useRef<AgGridReact>(null);
const firstTimeDataLoaded = useRef(true);
const firstTimeOnBodyScroll = useRef(true);
const allRowSelectedModeRef = useRef<boolean>(false);
const containerRef = useRef<HTMLDivElement>(null);
const totalHeight = footer ? heightProps + footerHeight : heightProps;
const tableHeight = footer ? heightProps - footerHeight : heightProps;

useImperativeHandle(ref, () => ({
setSelectedRows: (keys: number[]) => {
gridRef.current?.api?.forEachNode((node) => {
if (node?.data?.id && keys.includes(node.data.id)) {
node.setSelected(true);
} else {
node.setSelected(false);
}
});
},
unselectAll: () => {
setSelectedRowKeysPendingToRender([]);
gridRef.current?.api?.deselectAll();
},
refresh: () => {
gridRef.current?.api?.purgeInfiniteCache();
},
}));

const {
onHeaderCheckboxChange,
onSelectionChangedDebounced,
selectedRowKeysPendingToRender,
allRowSelectedMode,
internalSelectedRowKeys,
setSelectedRowKeysPendingToRender,
} = useRowSelection({
gridRef,
onRowSelectionChange,
onAllRowSelectedModeChange,
totalRows,
allRowSelectedModeProps,
});

useEffect(() => {
allRowSelectedModeRef.current = allRowSelectedMode;
}, [allRowSelectedMode]);

const columns = useDeepArrayMemo(columnsProps, "key");

const {
Expand Down Expand Up @@ -197,6 +184,10 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
return memo((props: { status: any }) => statusComponent(props.status));
}, [statusComponent]);

const selectedRowKeys = gridRef.current?.api
.getSelectedNodes()
.map((node) => node.data.id);

const colDefs = useMemo((): ColDef[] => {
const checkboxColumn = {
checkboxSelection: true,
Expand All @@ -211,12 +202,8 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
headerComponent: () => (
<HeaderCheckbox
totalRows={totalRows}
selectedRowKeysLength={internalSelectedRowKeys.length}
allRowSelected={
totalRows === internalSelectedRowKeys.length && totalRows > 0
}
allRowSelectedMode={allRowSelectedMode}
onHeaderCheckboxChange={onHeaderCheckboxChange}
selectedRowKeysLength={selectedRowKeys?.length || 0}
onSelectionCheckboxClicked={onSelectionCheckboxClicked}
/>
),
} as ColDef;
Expand Down Expand Up @@ -265,14 +252,13 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(

return finalColumns;
}, [
allRowSelectedMode,
columns,
columnsPersistedStateRef,
hasStatusColumn,
internalSelectedRowKeys.length,
onHeaderCheckboxChange,
columns,
MemoizedStatusComponent,
hasStatusColumn,
totalRows,
selectedRowKeys?.length,
onSelectionCheckboxClicked,
]);

const scrollToSavedPosition = useCallback(() => {
Expand All @@ -291,6 +277,7 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
},
[onRowStatus],
);

const getRows = useCallback(
async (params: IGetRowsParams) => {
gridRef.current?.api.showLoadingOverlay();
Expand Down Expand Up @@ -326,27 +313,14 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
: data;

params.successCallback(finalData, lastRow);
if (allRowSelectedModeRef.current) {
const selectedRowKeys = onGetSelectedRowKeys?.();

if (selectedRowKeys && selectedRowKeys.length > 0) {
gridRef?.current?.api.forEachNode((node) => {
node.setSelected(true);
if (node?.data?.id && selectedRowKeys.includes(node.data.id)) {
node.setSelected(true);
}
});
} else {
const selectedRowKeys = onGetSelectedRowKeys?.();
setSelectedRowKeysPendingToRender(selectedRowKeys || []);

if (selectedRowKeys && selectedRowKeys.length > 0) {
gridRef?.current?.api.forEachNode((node) => {
if (node?.data?.id && selectedRowKeys.includes(node.data.id)) {
// remove from selectedRowKeysPendingToRender
node.setSelected(true);
setSelectedRowKeysPendingToRender(
selectedRowKeysPendingToRender.filter(
(key) => node.data.id && key !== node.data.id,
),
);
}
});
}
}
gridRef.current?.api.hideOverlay();
if (firstTimeDataLoaded.current) {
Expand All @@ -361,8 +335,6 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
onGetSelectedRowKeys,
onRequestData,
scrollToSavedPosition,
selectedRowKeysPendingToRender,
setSelectedRowKeysPendingToRender,
],
);

Expand Down Expand Up @@ -396,6 +368,19 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
[onChangeFirstVisibleRowIndex],
);

useWhyDidYouRender("InfiniteTable", props);

const onSelectionChanged = useCallback(
(event: { api: { getSelectedNodes: () => any } }) => {
const allSelectedNodes = event.api.getSelectedNodes() || [];
const selectedKeys = allSelectedNodes.map(
(node: { data: any }) => node.data.id,
);
onRowSelectionChange?.(selectedKeys);
},
[onRowSelectionChange],
);

return (
<div
style={{
Expand Down Expand Up @@ -425,7 +410,7 @@ const InfiniteTableComp = forwardRef<InfiniteTableRef, InfiniteTableProps>(
onColumnResized={onColumnResized}
rowModelType={"infinite"}
cacheBlockSize={200}
onSelectionChanged={onSelectionChangedDebounced}
onSelectionChanged={onSelectionChanged}
cacheOverflowSize={2}
maxConcurrentDatasourceRequests={1}
infiniteInitialRowCount={50}
Expand All @@ -446,6 +431,8 @@ InfiniteTableComp.displayName = "InfiniteTable";

export const InfiniteTable = memo(InfiniteTableComp, (prevProps, nextProps) => {
return (
prevProps.onSelectionCheckboxClicked ===
nextProps.onSelectionCheckboxClicked &&
prevProps.onRowDoubleClick === nextProps.onRowDoubleClick &&
prevProps.onGetFirstVisibleRowIndex ===
nextProps.onGetFirstVisibleRowIndex &&
Expand Down
2 changes: 0 additions & 2 deletions src/components/InfiniteTable/useRowSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ export const useRowSelection = ({
onRowSelectionChange,
onAllRowSelectedModeChange,
totalRows,
allRowSelectedModeProps = false,
}: {
gridRef: RefObject<AgGridReact>;
onRowSelectionChange?: (selectedKeys: any[]) => void;
onAllRowSelectedModeChange?: (allRowSelectedMode: boolean) => void;
totalRows: number;
allRowSelectedModeProps?: boolean;
}) => {
const [internalSelectedRowKeys, setInternalSelectedRowKeys] = useState<any[]>(
[],
Expand Down

0 comments on commit 7647bfb

Please sign in to comment.