Skip to content

Commit

Permalink
fix(AnalyticalTable): offer limited support for infiniteScroll comb…
Browse files Browse the repository at this point in the history
…ined with a grouped table (#6431)

Using `infiniteScroll` with a grouped table can result in an odd user
experience. For example, when rows are lazy-loaded via scrolling, new
rows might only be added to existing groups. This won't change the
scroll container's height, potentially forcing the user to scroll down
again to load more rows.
Therefore (and as we don't have a concept for this behavior) __it's not
recommended using a grouped table in combination with
`infiniteScroll`__!
  • Loading branch information
Lukas742 authored Oct 2, 2024
1 parent b2942f8 commit ed48142
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { enrichEventWithDetails } from '@ui5/webcomponents-react-base';
import type { MutableRefObject } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import type { AnalyticalTablePropTypes } from '../types/index.js';
import type { AnalyticalTablePropTypes, TableInstance } from '../types/index.js';

interface VirtualTableBodyContainerProps {
tableBodyHeight: number;
Expand All @@ -12,13 +12,14 @@ interface VirtualTableBodyContainerProps {
infiniteScroll?: AnalyticalTablePropTypes['infiniteScroll'];
infiniteScrollThreshold?: AnalyticalTablePropTypes['infiniteScrollThreshold'];
onLoadMore: AnalyticalTablePropTypes['onLoadMore'];
rows: Record<string, any>[];
rows: TableInstance['rows'];
internalRowHeight: number;
handleExternalScroll: AnalyticalTablePropTypes['onTableScroll'];
visibleRows: number;
popInRowHeight: number;
rowCollapsedFlag?: boolean;
dispatch: (e: { type: string; payload?: any }) => void;
isGrouped: boolean;
}

export const VirtualTableBodyContainer = (props: VirtualTableBodyContainerProps) => {
Expand All @@ -37,6 +38,7 @@ export const VirtualTableBodyContainer = (props: VirtualTableBodyContainerProps)
visibleRows,
popInRowHeight,
rowCollapsedFlag,
isGrouped,
dispatch
} = props;
const [isMounted, setIsMounted] = useState(false);
Expand Down Expand Up @@ -75,13 +77,19 @@ export const VirtualTableBodyContainer = (props: VirtualTableBodyContainerProps)
handleExternalScroll(enrichEventWithDetails(event, { rows, rowElements: event.target.children[0].children }));
const scrollOffset = event.target.scrollTop;
const isScrollingDown = lastScrollTop.current < scrollOffset;
if (isScrollingDown && infiniteScroll) {
const target = event.target;
const scrolledToBottom = target.scrollHeight - target.scrollTop === target.clientHeight;
// For a grouped table, it is possible that no new groups (rows) are added since new rows are added to existing groups.
// Because of this, the table should trigger the `onLoadMore` event every time a user scrolls to the bottom.
const applyGroupingLogic = scrolledToBottom && isGrouped;

if ((isScrollingDown || applyGroupingLogic) && infiniteScroll) {
lastScrollTop.current = scrollOffset;
const currentLastRow =
Math.floor(scrollOffset / popInRowHeight) +
(popInRowHeight === internalRowHeight ? visibleRows : Math.floor(tableBodyHeight / popInRowHeight));
if (rows.length - currentLastRow < infiniteScrollThreshold) {
if (!firedInfiniteLoadEvents.current.has(rows.length)) {
if (rows.length - currentLastRow < infiniteScrollThreshold || applyGroupingLogic) {
if (!firedInfiniteLoadEvents.current.has(rows.length) || applyGroupingLogic) {
onLoadMore(event);
}
firedInfiniteLoadEvents.current.add(rows.length);
Expand Down
2 changes: 2 additions & 0 deletions packages/main/src/components/AnalyticalTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp

const tableState: AnalyticalTableState = tableInstanceRef.current.state;
const { triggerScroll } = tableState;
const isGrouped = !!tableState.groupBy.length;

const noDataTextI18n = i18nBundle.getText(LIST_NO_DATA);
const noDataTextFiltered = i18nBundle.getText(NO_DATA_FILTERED);
Expand Down Expand Up @@ -800,6 +801,7 @@ const AnalyticalTable = forwardRef<AnalyticalTableDomRef, AnalyticalTablePropTyp
rows={rows}
handleExternalScroll={handleBodyScroll}
visibleRows={internalVisibleRowCount}
isGrouped={isGrouped}
>
<VirtualTableBody
scrollContainerRef={scrollContainerRef}
Expand Down
4 changes: 4 additions & 0 deletions packages/main/src/components/AnalyticalTable/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,8 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
* Defines whether columns are groupable.
*
* __Note:__ This prop has no effect when `isTreeTable` is true or `renderRowSubComponent` is set.
*
* __Note:__ It is not recommended to use grouping in combination with `infiniteScroll` as there is no concept for this configuration.
*/
groupable?: boolean;
/**
Expand Down Expand Up @@ -746,6 +748,8 @@ export interface AnalyticalTablePropTypes extends Omit<CommonProps, 'title'> {
columnOrder?: string[];
/**
* Defines whether infinite scroll is active.
*
* __Note:__ It is not recommended to use this prop in combination with a grouped table, as there is no concept for this configuration.
*/
infiniteScroll?: boolean;
/**
Expand Down

0 comments on commit ed48142

Please sign in to comment.