React-virtualized: ColumnSizer fixed width column?

Created on 12 Jun 2017  路  3Comments  路  Source: bvaughn/react-virtualized

Hi there,

I was wondering if there's a way to use ColumnSizer but specify that a column needs to be fixed width.

Right now as I understand, ColumnSizer will take all the columns and evenly disperse them to the width prop provided. Could you provide a prop such as fixedWidthColumns which takes [{index: 0, width: 120}, {index: 3, width: 200}] as to allow us to provide static widths to columns of our choosing?

I ask because I'm using ColumnResizer along with MultiGrid to create a table, which works beautifully. But I always have a checkbox in the first column which only needs to be 75px wide.

Love the library btw @bvaughn, complete joy to use :)

Most helpful comment

Hey @johnnyji,

Thank for the complement. 馃槃 Much appreciated.

What you're asking to do should be possible without a change to ColumnSizer by doing something like this:

// You proposed a data structure like this:
const fixedWidthColumns = [
  {index: 0, width: 120},
  {index: 3, width: 200}
];

// But I would propose you use something more like this for faster lookups:
const fixedWidthColumns = {
  0: 120,
  3: 200
};

// You can calculate their total width like so:
const fixedColumnWidths = Object.keys(fixedWidthColumns).reduce(
  (totalWidth, key) => totalWidth + fixedWidthColumns[key],
  0
);

// And subtrace the fixed widths from what you pass to ColumnSize:
const dynamicColumnWidth = width - fixedColumnWidths;

// Then pass ColumnSizer a width-getter that's aware of your approach:
const getColumnWidthHelper = (getColumnWidth) => ({ index }) =>
  fixedColumnWidths.hasOwnProperty(index)
    ? fixedWidthColumns[index]
    : getColumnWidth({ index })

// You could do this:
<ColumnSizer
  columnMaxWidth={100}
  columnMinWidth={50}
  columnCount={numColumns}
  width={dynamicColumnWidth}
>
  {({ adjustedWidth, getColumnWidth, registerChild }) => (
    <Grid
      ref={registerChild}
      columnWidth={getColumnWidthHelper(getColumnWidth)}
      columnCount={numColumns}
      height={someCalculatedHeight}
      cellRenderer={someCellRenderer}
      rowHeight={50}
      rowCount={numRows}
      width={adjustedWidth + fixedColumnWidths}
    />
  )}
</ColumnSizer>

I didn't test the above so there may be minor issues but I think the general approach should work. 馃槃

If you'd like to submit a PR that adds something to ColumnSizer I'll be happy to review it. Whether it gets merged will depend on how much complexity it adds to the component though. Cheers!

All 3 comments

Hey @johnnyji,

Thank for the complement. 馃槃 Much appreciated.

What you're asking to do should be possible without a change to ColumnSizer by doing something like this:

// You proposed a data structure like this:
const fixedWidthColumns = [
  {index: 0, width: 120},
  {index: 3, width: 200}
];

// But I would propose you use something more like this for faster lookups:
const fixedWidthColumns = {
  0: 120,
  3: 200
};

// You can calculate their total width like so:
const fixedColumnWidths = Object.keys(fixedWidthColumns).reduce(
  (totalWidth, key) => totalWidth + fixedWidthColumns[key],
  0
);

// And subtrace the fixed widths from what you pass to ColumnSize:
const dynamicColumnWidth = width - fixedColumnWidths;

// Then pass ColumnSizer a width-getter that's aware of your approach:
const getColumnWidthHelper = (getColumnWidth) => ({ index }) =>
  fixedColumnWidths.hasOwnProperty(index)
    ? fixedWidthColumns[index]
    : getColumnWidth({ index })

// You could do this:
<ColumnSizer
  columnMaxWidth={100}
  columnMinWidth={50}
  columnCount={numColumns}
  width={dynamicColumnWidth}
>
  {({ adjustedWidth, getColumnWidth, registerChild }) => (
    <Grid
      ref={registerChild}
      columnWidth={getColumnWidthHelper(getColumnWidth)}
      columnCount={numColumns}
      height={someCalculatedHeight}
      cellRenderer={someCellRenderer}
      rowHeight={50}
      rowCount={numRows}
      width={adjustedWidth + fixedColumnWidths}
    />
  )}
</ColumnSizer>

I didn't test the above so there may be minor issues but I think the general approach should work. 馃槃

If you'd like to submit a PR that adds something to ColumnSizer I'll be happy to review it. Whether it gets merged will depend on how much complexity it adds to the component though. Cheers!

Thanks for this clever solution!

Small note for anyone using this snippet, you need to replace fixedColumnWidths with fixedWidthColumns in the getColumnWidthHelper like so:

// Then pass ColumnSizer a width-getter that's aware of your approach:
const getColumnWidthHelper = (getColumnWidth) => ({ index }) =>
  fixedWidthColumns.hasOwnProperty(index)
    ? fixedWidthColumns[index]
    : getColumnWidth({ index })

Another small thing, seems like ColumnSizer's columnCount should only receive the dynamic columns count like so:

<ColumnSizer
  columnMaxWidth={500}
  columnMinWidth={150}
  columnCount={columnCount-Object.keys(fixedWidthColumns).length}
  key="GridColumnSizer"
  width={dynamicColumnWidth}
>
Was this page helpful?
0 / 5 - 0 ratings