reactgrid icon indicating copy to clipboard operation
reactgrid copied to clipboard

Sticky rows/columns not working properly with rowspan/colspan

Open jvloo opened this issue 1 year ago • 5 comments

Describe the bug Sticky rows and columns are not functioning correctly when sticky cells use rowspan or colspan.

Current behavior

  • If a sticky row has a rowspan, it is not sticking properly. Image

  • If a sticky column has a colspan, the sticky behavior is also not working as expected. Image

Your environment details

  • Device: desktop
  • OS: Windows 11
  • Browser: Edge
  • ReactGrid Version: v5-latest

jvloo avatar Mar 25 '25 09:03 jvloo

@jvloo Can you share your cells implementation? Note that spanned cells defined in a certain pane shouldn't exceed it.

webloopbox avatar Mar 25 '25 09:03 webloopbox

@jvloo Can you share your cells implementation? Note that spanned cells defined in a certain pane shouldn't exceed it.

Sure, I have simplified the code for your review.

Below is for the spanned rows:

const defaultRowColumns: Column[][] = useMemo(() => {
    const rowCols_1: Column[] = [
      {
        colIndex: 0,
        name: '',
        rowSpan: 2,
        minWidth: 0,
        width: 30,
      },
      {
        colIndex: 1,
        name: 'ID',
        rowSpan: 2,
        minWidth: 0,
        width: 70,
      },
      {
        colIndex: 2,
        name: '',
        rowSpan: 2,
        minWidth: 0,
        width: 210,
      },
      {
        colIndex: 3,
        name: 'Escalation',
        rowSpan: 2,
        minWidth: 0,
        width: 110,
      },
      {
        colIndex: 4,
        name: 'Frequency',
        rowSpan: 2,
        minWidth: 0,
        width: 110,
      },
      {
        colIndex: 5,
        name: 'Start',
        rowSpan: 2,
        minWidth: 0,
        width: 70,
      },
      {
        colIndex: 6,
        name: 'End',
        rowSpan: 2,
        minWidth: 0,
        width: 70,
      },
      {
        colIndex: 7,
        name: 'Contract Value',
        rowSpan: 2,
        minWidth: 0,
        width: 100,
      },
      {
        colIndex: 8,
        name: 'Amount per Freq.',
        rowSpan: 2,
        minWidth: 0,
        width: 100,
      },
      {
        colIndex: 9,
        key: 'actualToDate',
        name: 'To Date & To Go',
        minWidth: 0,
        width: 110
      },
      {
        colIndex: 10,
        key: 'forecastToGo',
        name: '',
        minWidth: 0,
        width: 110
      },
      {
        colIndex: 11,
        name: 'Total Amount',
        rowSpan: 2,
        minWidth: 0,
        width: 90,
      }
    );

    // Set second row columns
    const rowCols_2: Column[] = rowCols_1.map((col) => {
      let name = '';
      switch (col.key) {
        case 'actualToDate':
          name = 'Actual To Date';
          break;
        case 'forecastToGo':
          name = 'Forecast To Go';
          break;
      }
      return {
        ...col,
        name,
        rowSpan: 1,
      };
    });
    return [rowCols_1, rowCols_2];
  }, []);

  const dateColumns = useMemo(() => {
    const columns: Column[] = [];
    const startDate = new Date();

    for (let i = 0; i < 20; i++) {
      const currentDate = addMonths(startDate, i); // addMonths from date-fns
      columns.push({
        colIndex: i,
        name: currentDate,
        minWidth: 0,
        width: 80,
      });
    }

    return columns;
  }, []);

  const allRowColumns = useMemo<Column[][]>(() => {
    const rowColumns = cloneDeep(defaultRowColumns);
    const dateCols = dateColumns.map((column, idx) => ({
      ...column,
      colIndex: defaultRowColumns[0].length + idx,
      rowSpan: 2,
    }));
    rowColumns.map((cols) => cols.push(...dateCols));
    return rowColumns;
  }, [defaultRowColumns, dateColumns]);

const stickyTopRows = 2;

jvloo avatar Mar 25 '25 10:03 jvloo

@jvloo Can you share your cells implementation? Note that spanned cells defined in a certain pane shouldn't exceed it.

For the spanned columns:

  const defaulColumns: Column[][] = useMemo(() => {
    const rowCols_1: Column[] = [
      { name: '', colIndex: 0, minWidth: 25, width: 50 },
      { name: 'Child2', colIndex: 1, colSpan: 2, minWidth: 50, width: 90 },
      { name: 'Child1', colIndex: 3, colSpan: 2, minWidth: 50, width: 90 },
      { name: 'Parent', colIndex: 5, colSpan: 2, minWidth: 50, width: 90 },
      { name: 'Total', colIndex: 7, rowSpan: 2, minWidth: 50, width: 72 },
    ];
    const rowCols_2: Column[] = [
      { name: '', colIndex: 0, minWidth: 25, width: 50 },
      { name: 'ID', colIndex: 1, minWidth: 50, width: 90 },
      { name: 'Description', colIndex: 2, minWidth: 50, width: 200 },
      { name: 'ID', colIndex: 3, minWidth: 50, width: 90 },
      { name: 'Description', colIndex: 4, minWidth: 50, width: 200 },
      { name: 'ID', colIndex: 5, minWidth: 50, width: 90 },
      { name: 'Description', colIndex: 6, minWidth: 50, width: 200 },
      { name: '', colIndex: 7, minWidth: 50, width: 72 },
    ];
    return [rowCols_1, rowCols_2];
  }, []);

  const dateColumns = useMemo(() => {
    const columns: Column[] = [];
    const startDate = new Date();

    for (let i = 0; i < 20; i++) {
      const currentDate = addMonths(startDate, i); // addMonths from date-fns
      columns.push({
        colIndex: i,
        name: currentDate,
        minWidth: 0,
        width: 80,
      });
    }

    return columns;
  }, []);

  const allRowColumns = useMemo<Column[][]>(() => {
    const rowColumns = cloneDeep(defaultRowColumns);
    const dateCols = dateColumns.map((column, idx) => ({
      ...column,
      colIndex: defaultRowColumns[0].length + idx,
      rowSpan: 2,
    }));
    rowColumns.map((cols) => cols.push(...dateCols));
    return rowColumns;
  }, [defaultRowColumns, dateColumns]);

const stickyLeftColumns = 8;

jvloo avatar Mar 25 '25 10:03 jvloo

I don’t see how the cells passed directly to the ReactGrid component are defined. However, based on the provided code, I suspect that each cell receives colSpan and rowSpan in the columns and rows specified by stickyLeftColumns and stickyTopRows. This could result in some cells being overlapped.

I suggest reviewing the cells array you’ve defined to ensure there are no position conflicts. For example, here’s an incorrect cell implementation where a cell with colSpan: 2overlaps another cell: [{ colIndex: 0, rowIndex: 0, colSpan: 2 }, { colIndex: 1, rowIndex: 0 }].

webloopbox avatar Mar 26 '25 09:03 webloopbox