Skip to content

Commit

Permalink
Sticky columns
Browse files Browse the repository at this point in the history
- added sticky columns working to default-pagination-table.js
  • Loading branch information
prajapati-parth committed Jul 13, 2017
1 parent c6c52a7 commit 369be1c
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 8 deletions.
47 changes: 43 additions & 4 deletions examples/js/pagination/default-pagination-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,58 @@ addProducts(70);
export default class DefaultPaginationTable extends React.Component {
constructor(props) {
super(props);
this.state = {
stickyColumnShown: false
};
}

componentDidMount() {
window.addEventListener('resize', this.updateDimensions.bind(this));
this.updateDimensions();
}

componentWillUnmount() {
window.removeEventListener('resize', this.updateDimensions.bind(this));
}

render() {
return (
<div>
<BootstrapTable
data={ products }
pagination>
<TableHeaderColumn dataField='id' isKey={ true }>Product ID</TableHeaderColumn>
<TableHeaderColumn dataField='name'>Product Name</TableHeaderColumn>
<TableHeaderColumn dataField='price'>Product Price</TableHeaderColumn>
pagination
showStickyColumn={ this.state.stickyColumnShown }
ref='bsTable'>
<TableHeaderColumn width='200' dataField='name'>Product Name</TableHeaderColumn>
<TableHeaderColumn width='200' dataField='id' isKey={ true }>Product ID</TableHeaderColumn>
<TableHeaderColumn width='200' dataField='id'>Product ID</TableHeaderColumn>
<TableHeaderColumn width='200' dataField='price'>Product Price</TableHeaderColumn>
<TableHeaderColumn width='200' dataField='price'>Product Price</TableHeaderColumn>
</BootstrapTable>
</div>
);
}

updateDimensions() {
if (window.screen.width <= 766) {
const sizePerPage = this.refs.bsTable.getSizePerPage();
if (!this.state.stickyColumnShown) {
this.setState({
stickyColumnShown: true
});
for (let i = 0; i < sizePerPage; i++) {
this.refs.bsTable.setRowHeight(i, this.refs.bsTable.getRowHeight(i));
}
}
} else {
this.setState({
stickyColumnShown: false
});
}
}

handleButtonClick() {
// console.log(this.refs.bsTable.getRowHeight(1));
this.refs.bsTable.setRowHeight(1, 70);
}
}
16 changes: 13 additions & 3 deletions src/BootstrapTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ class BootstrapTable extends Component {
reset={ this.state.reset }
expandColumnVisible={ expandColumnOptions.expandColumnVisible }
expandColumnComponent={ expandColumnOptions.expandColumnComponent }
expandColumnBeforeSelectColumn={ expandColumnOptions.expandColumnBeforeSelectColumn }>
expandColumnBeforeSelectColumn={ expandColumnOptions.expandColumnBeforeSelectColumn }
showStickyColumn={ this.props.showStickyColumn }>
{ this.props.children }
</TableHeader>
<TableBody ref='body'
Expand Down Expand Up @@ -461,7 +462,8 @@ class BootstrapTable extends Component {
keyBoardNav={ this.props.keyBoardNav }
onNavigateCell={ this.handleNavigateCell }
x={ this.state.x }
y={ this.state.y } />
y={ this.state.y }
showStickyColumn={ this.props.showStickyColumn } />
</div>
{ tableFilter }
{ showPaginationOnBottom ? pagination : null }
Expand Down Expand Up @@ -662,7 +664,7 @@ class BootstrapTable extends Component {
handleRowClick = (row, rowIndex, columnIndex) => {
const { options, keyBoardNav } = this.props;
if (options.onRowClick) {
options.onRowClick(row, columnIndex);
options.onRowClick(row, columnIndex, rowIndex);
}
if (keyBoardNav) {
let { clickToNav } = typeof keyBoardNav === 'object' ? keyBoardNav : {};
Expand Down Expand Up @@ -1282,6 +1284,14 @@ class BootstrapTable extends Component {
}
}

getRowHeight(idx) {
return this.refs.body.getTableColumnHeight(idx);
}

setRowHeight(idx, height) {
return this.refs.body.setTableRowHeight(idx, height);
}

_scrollTop = () => {
const { scrollTop } = this.props;
if (scrollTop === Const.SCROLL_TOP) {
Expand Down
172 changes: 172 additions & 0 deletions src/TableBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,161 @@ class TableBody extends Component {
expandColSpan += 1;
}

const stickyTableRows = this.props.data.map(function(data, r) {
const tableColumns = this.props.columns.filter(_ => _ != null).map(function(column, i) {
if ( i === 0 ) {
const fieldValue = data[column.name];
const isFocusCell = r === y && i === x;
if (column.name !== this.props.keyField && // Key field can't be edit
column.editable && // column is editable? default is true, user can set it false
column.editable.readOnly !== true &&
this.state.currEditCell !== null &&
this.state.currEditCell.rid === r &&
this.state.currEditCell.cid === i &&
noneditableRows.indexOf(data[this.props.keyField]) === -1) {
let editable = column.editable;
const format = column.format ? function(value) {
return column.format(value, data, column.formatExtraData, r).replace(/<.*?>/g, '');
} : false;
if (Utils.isFunction(column.editable)) {
editable = column.editable(fieldValue, data, r, i);
}

return (
<TableEditColumn
completeEdit={ this.handleCompleteEditCell }
// add by bluespring for column editor customize
editable={ editable }
customEditor={ column.customEditor }
format={ column.format ? format : false }
key={ i }
blurToSave={ cellEdit.blurToSave }
onTab={ this.handleEditCell }
rowIndex={ r }
colIndex={ i }
row={ data }
fieldValue={ fieldValue }
className={ column.editClassName }
invalidColumnClassName={ column.invalidEditColumnClassName }
beforeShowError={ beforeShowError }
isFocus={ isFocusCell }
customStyleWithNav={ customEditAndNavStyle } />
);
} else {
// add by bluespring for className customize
let columnChild = fieldValue && fieldValue.toString();
let columnTitle = null;
let tdClassName = column.className;
const customTDstyle = { border: 'none', borderTop: '1px solid #ddd', display: 'table-cell' };
if (Utils.isFunction(column.className)) {
tdClassName = column.className(fieldValue, data, r, i);
}

if (typeof column.format !== 'undefined') {
const formattedValue = column.format(fieldValue, data, column.formatExtraData, r);
if (!React.isValidElement(formattedValue)) {
columnChild = (
<div dangerouslySetInnerHTML={ { __html: formattedValue } }></div>
);
} else {
columnChild = formattedValue;
columnTitle = column.columnTitle && formattedValue ? formattedValue.toString() : null;
}
} else {
columnTitle = column.columnTitle && fieldValue ? fieldValue.toString() : null;
}
return (
<TableColumn key={ i }
rIndex={ r }
dataAlign={ column.align }
className={ tdClassName }
columnTitle={ columnTitle }
cellEdit={ cellEdit }
hidden={ column.hidden }
onEdit={ this.handleEditCell }
width={ column.width }
onClick={ this.handleClickCell }
attrs={ column.attrs }
style={ { ...column.style, ...customTDstyle } }
tabIndex={ (tabIndex++) + '' }
isFocus={ isFocusCell }
keyBoardNav={ enableKeyBoardNav }
onKeyDown={ this.handleCellKeyDown }
customNavStyle={ customNavStyle }
row={ data }>
{ columnChild }
</TableColumn>
);
}
}
}, this);
const key = data[this.props.keyField];
const disable = unselectable.indexOf(key) !== -1;
const selected = this.props.selectedRowKeys.indexOf(key) !== -1;
const selectRowColumn = isSelectRowDefined && !this.props.selectRow.hideSelectColumn ?
this.renderSelectRowColumn(selected, inputType, disable, CustomComponent, r, data) : null;
const expandedRowColumn = this.renderExpandRowColumn(
this.props.expandableRow && this.props.expandableRow(data),
this.props.expanding.indexOf(key) > -1,
ExpandColumnCustomComponent, r, data
);
const haveExpandContent = this.props.expandableRow && this.props.expandableRow(data);
const isExpanding = haveExpandContent && this.props.expanding.indexOf(key) > -1;

// add by bluespring for className customize
let trClassName = this.props.trClassName;
if (Utils.isFunction(this.props.trClassName)) {
trClassName = this.props.trClassName(data, r);
}
if (isExpanding && this.props.expandParentClass) {
trClassName += Utils.isFunction(this.props.expandParentClass) ?
this.props.expandParentClass(data, r) :
this.props.expandParentClass;
}
const result = [ <TableRow isSelected={ selected } key={ key } className={ trClassName }
ref={ 'stickyTableRow' + r }
style={ { display: 'table-row' } }
index={ r }
row={ data }
selectRow={ isSelectRowDefined ? this.props.selectRow : undefined }
enableCellEdit={ cellEdit.mode !== Const.CELL_EDIT_NONE }
onRowClick={ this.handleRowClick }
onRowDoubleClick={ this.handleRowDoubleClick }
onRowMouseOver={ this.handleRowMouseOver }
onRowMouseOut={ this.handleRowMouseOut }
onSelectRow={ this.handleSelectRow }
onExpandRow={ this.handleClickCell }
unselectableRow={ disable }>
{ this.props.expandColumnOptions.expandColumnVisible &&
this.props.expandColumnOptions.expandColumnBeforeSelectColumn &&
expandedRowColumn }
{ selectRowColumn }
{ this.props.expandColumnOptions.expandColumnVisible &&
!this.props.expandColumnOptions.expandColumnBeforeSelectColumn &&
expandedRowColumn }
{ tableColumns }
</TableRow> ];

if (haveExpandContent) {
const expandBodyClass = Utils.isFunction(this.props.expandBodyClass) ?
this.props.expandBodyClass(data, r, isExpanding) :
this.props.expandBodyClass;
result.push(
<ExpandComponent
key={ key + '-expand' }
row={ data }
className={ expandBodyClass }
bgColor={ this.props.expandRowBgColor || this.props.selectRow.bgColor || undefined }
hidden={ !isExpanding }
colSpan={ expandColSpan }
width={ "100%" }>
{ this.props.expandComponent(data) }
</ExpandComponent>
);
}
return (result);
}, this);

let tableRows = this.props.data.map(function(data, r) {
const tableColumns = this.props.columns.filter(_ => _ != null).map(function(column, i) {
const fieldValue = data[column.name];
Expand Down Expand Up @@ -157,6 +312,7 @@ class TableBody extends Component {
this.props.expandParentClass;
}
const result = [ <TableRow isSelected={ selected } key={ key } className={ trClassName }
ref={ 'tableRow' + r }
index={ r }
row={ data }
selectRow={ isSelectRowDefined ? this.props.selectRow : undefined }
Expand Down Expand Up @@ -217,6 +373,12 @@ class TableBody extends Component {
<div ref='container'
className={ classSet('react-bs-container-body', this.props.bodyContainerClass) }
style={ this.props.style }>
<table className={ tableClasses } style={ { position: 'absolute', display: this.props.showStickyColumn ? 'block' : 'none', width: 'initial', backgroundColor: '#FFFFFF', borderRight: '1px solid #ddd' } }>
{ React.cloneElement(tableHeader) }
<tbody ref='tbody'>
{ stickyTableRows }
</tbody>
</table>
<table className={ tableClasses }>
{ React.cloneElement(tableHeader, { ref: 'header' }) }
<tbody ref='tbody'>
Expand Down Expand Up @@ -483,6 +645,16 @@ class TableBody extends Component {
);
}

getTableColumnHeight(refValue) {
const reference = 'tableRow' + refValue;
return this.refs[reference].getTableRowHeight();
}

setTableRowHeight(refValue, height) {
const reference = 'stickyTableRow' + refValue;
this.refs[reference].setTableRowHeight(height);
}

_isSelectRowDefined() {
return this.props.selectRow.mode === Const.ROW_SELECT_SINGLE ||
this.props.selectRow.mode === Const.ROW_SELECT_MULTI;
Expand Down
19 changes: 19 additions & 0 deletions src/TableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class TableHeader extends Component {
));

const rows = [];
const stickyRows = [];
let rowKey = 0;

rows[0] = [];
Expand Down Expand Up @@ -87,6 +88,12 @@ class TableHeader extends Component {
elm, { key: rowKey++, isOnlyHead: true }
));
}

if ((rowSpan + rowIndex) === 1) {
stickyRows.push(React.cloneElement(
elm, { reset, key: rowKey++, onSort, sort, sortIndicator, isOnlyHead: false }
));
}
});

const trs = rows.map((row, indexRow)=>{
Expand All @@ -97,8 +104,20 @@ class TableHeader extends Component {
);
});

const stickytrs = (
<tr key={ 0 }>
{ stickyRows[0] }
</tr>
);

return (
<div ref='container' className={ containerClasses } style={ this.props.style }>
<table className={ tableClasses } style={ { position: 'absolute', display: this.props.showStickyColumn ? 'block' : 'none', width: 'initial', backgroundColor: '#FFFFFF' } }>
{ React.cloneElement(this.props.colGroups) }
<thead ref='header'>
{ stickytrs }
</thead>
</table>
<table className={ tableClasses }>
{ React.cloneElement(this.props.colGroups, { ref: 'headerGrp' }) }
<thead ref='header'>
Expand Down
18 changes: 17 additions & 1 deletion src/TableRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ class TableRow extends Component {
constructor(props) {
super(props);
this.clickNum = 0;
this.state = {
customStyle: {}
};
}

rowClick = e => {
Expand Down Expand Up @@ -91,13 +94,26 @@ class TableRow extends Component {
};

return (
<tr { ...trCss }
<tr ref='tableRowNative' { ...trCss }
style={ { ...this.props.style, ...this.state.customStyle } }
onMouseOver={ this.rowMouseOver }
onMouseOut={ this.rowMouseOut }
onClick={ this.rowClick }
onDoubleClick={ this.rowDoubleClick }>{ this.props.children }</tr>
);
}

getTableRowHeight() {
return this.refs.tableRowNative.clientHeight;
}

setTableRowHeight(height) {
this.setState({
customStyle: {
height
}
});
}
}
TableRow.propTypes = {
index: PropTypes.number,
Expand Down

0 comments on commit 369be1c

Please sign in to comment.