Skip to content

Instantly share code, notes, and snippets.

@ardok
Last active August 16, 2017 21:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ardok/4aa9500f5dae3b462427b7cd54404176 to your computer and use it in GitHub Desktop.
Save ardok/4aa9500f5dae3b462427b7cd54404176 to your computer and use it in GitHub Desktop.
Fixed Data Table 2 Wrapper to have fixed right columns!
/* eslint-disable no-return-assign */
import React, {Component} from 'react';
import debounce from 'debounce';
import {Table, Column} from 'fixed-data-table-2';
function setHeadersFixed(containerEl) {
const els = containerEl.getElementsByClassName('fixedDataTableLayout_header');
[].forEach.call(els, (el) => {
const parentNode = el.parentNode;
parentNode.style.position = 'fixed';
parentNode.style.top = 0;
});
}
function resetHeadersFixed(containerEl) {
const els = containerEl.getElementsByClassName('fixedDataTableLayout_header');
[].forEach.call(els, (el) => {
const parentNode = el.parentNode;
parentNode.style.position = 'inherit';
});
}
const scrollbarWidth = 17;
const debounceTimeout = 250;
/*
This table will have height to fit the entire rows. So expect no vertical scrolling.
*/
export default class FixedDataTableWrapper extends Component {
props: {
rowHeight: number,
headerHeight: number,
rowsCount: number,
width?: number,
rowData: Array<{[columnKey: string]: mixed}>,
// This is @ardo invention, to make headers fixed
fixedHeaders?: boolean,
columns: Array<{
columnKey: string,
header: string|React$Element<*>|React$Component<*, *, *>,
cell: string|React$Element<*>|React$Component<*, *, *>,
width: number,
allowCellsRecycling: boolean,
pureRendering: boolean,
// Default `fixed` is for left fixed
fixed: boolean,
// This is @ardo invention, to make it fixed on right side
fixedRight: boolean,
}>,
};
state: {
tableWidth: number,
tableHeight: number,
};
constructor(props) {
super(props);
this.state = {
tableWidth: 0,
tableHeight: 0,
};
this.containerEl = null;
}
componentDidMount() {
const {fixedHeaders} = this.props;
window.addEventListener('resize', this.onResize, false);
if (fixedHeaders) {
window.addEventListener('scroll', this.onScroll, false);
}
setTimeout(() => {
this.onResize();
this.onScroll();
}, debounceTimeout);
}
componentWillUnmount() {
window.removeEventListener('resize', this.onResize);
if (this.props.fixedHeaders) {
window.removeEventListener('scroll', this.onScroll);
}
}
onResize = debounce(() => {
const {width, rowData, rowHeight, headerHeight} = this.props;
const nextState = {};
if (width === undefined) {
nextState.tableWidth = this.containerEl.offsetWidth;
}
nextState.tableHeight = rowData.length * rowHeight + headerHeight + scrollbarWidth;
this.setState(nextState);
}, debounceTimeout);
onScroll = debounce(() => {
const {headerHeight} = this.props;
const containerTop = this.containerEl.offsetTop;
const scrollTop = document.body.scrollTop;
if (scrollTop > containerTop &&
scrollTop < (containerTop + this.containerEl.offsetHeight - headerHeight - scrollbarWidth)) {
// Only make it fixed if the scroll is in between of the table element
setHeadersFixed(this.containerEl);
} else {
resetHeadersFixed(this.containerEl);
}
}, debounceTimeout);
getTotalFixedRightColsWidth() {
return this.props.columns.reduce((final, {fixedRight, width}) => (
fixedRight ? (final + width) : final
), 0);
}
buildColumns() {
const {columns} = this.props;
return columns.reduce((final, col) => {
if (!col.fixedRight) {
final.push(
<Column key={col.columnKey} {...col} />
);
}
return final;
}, []);
}
buildFixedRightTable(totalFixedRightColsWidth) {
const {tableHeight} = this.state;
/* eslint-disable no-unused-vars */
const {rowData, columns, ...otherProps} = this.props;
/* eslint-enable no-unused-vars */
// Find the fixedRight
const rightFixedCols = columns.reduce((final, col) => {
const {fixedRight, ...rest} = col;
if (fixedRight) {
final.push(
<Column key={col.columnKey} {...rest} />
);
}
return final;
}, []);
if (rightFixedCols.length === 0) {
return null;
}
return (
<Table {...otherProps} height={tableHeight} width={totalFixedRightColsWidth || this.getTotalFixedRightColsWidth()}>
{rightFixedCols}
</Table>
);
}
render() {
/* eslint-disable no-unused-vars */
const {rowData, columns, ...otherProps} = this.props;
/* eslint-enable no-unused-vars */
const {tableWidth, tableHeight} = this.state;
const totalFixedRightColsWidth = this.getTotalFixedRightColsWidth();
return (
<div ref={(c) => this.containerEl = c} style={{display: 'flex'}}>
<Table {...otherProps} width={tableWidth - totalFixedRightColsWidth} height={tableHeight}>
{this.buildColumns()}
</Table>
{this.buildFixedRightTable(totalFixedRightColsWidth)}
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment