Skip to content

Instantly share code, notes, and snippets.

@ZackKnopp
Created November 29, 2018 15:37
Show Gist options
  • Save ZackKnopp/40fc0691feb03f0fba3e25e7353b73ae to your computer and use it in GitHub Desktop.
Save ZackKnopp/40fc0691feb03f0fba3e25e7353b73ae to your computer and use it in GitHub Desktop.
Copy paste selection range for react-data-grid
// Fix for copy cell in react-data-grid showing up
.react-grid-cell-copied {
display: none;
}
// Tested with react-data-grid v5.0.4, earlier versions MAY NOT HAVE cellRangeSelection
// And it won't show any errors if you try this with an earlier version, so use at least v5.0.4
import React, { Component } from 'react';
import { range } from 'lodash';
import ReactDataGrid from 'react-data-grid'; // Tested with v5.0.4, earlier versions MAY NOT HAVE cellRangeSelection
const columns = [
{ key: 'id', name: 'ID', editable: true },
{ key: 'title', name: 'Title', editable: true },
{ key: 'count', name: 'Complete', editable: true },
{ key: 'sarah', name: 'Sarah', editable: true },
{ key: 'jessica', name: 'Jessica', editable: true },
];
const initialRows = Array.from(Array(1000).keys(), (_, x) => (
{ id: x, title: x * 2, count: x * 3, sarah: x * 4, jessica: x * 5 }
));
const defaultParsePaste = str => (
str.split(/\r\n|\n|\r/)
.map(row => row.split('\t'))
);
class MyDataGrid extends Component {
constructor(props) {
super(props);
this.state = {
rows: initialRows,
topLeft: {},
botRight: {},
};
// Copy paste event handler
document.addEventListener('copy', this.handleCopy);
document.addEventListener('paste', this.handlePaste);
}
componentWillUnmount() {
this.removeAllListeners();
}
removeAllListeners = () => {
document.removeEventListener('copy', this.handleCopy);
document.removeEventListener('paste', this.handlePaste);
}
rowGetter = (i) => {
const { rows } = this.state;
return rows[i];
}
updateRows = (startIdx, newRows) => {
this.setState((state) => {
const rows = state.rows.slice();
for (let i = 0; i < newRows.length; i++) {
if (startIdx + i < rows.length) {
rows[startIdx + i] = { ...rows[startIdx + i], ...newRows[i] };
}
}
return { rows };
});
}
handleCopy = (e) => {
console.debug('handleCopy Called');
e.preventDefault();
const { topLeft, botRight } = this.state;
// Loop through each row
const text = range(topLeft.rowIdx, botRight.rowIdx + 1).map(
// Loop through each column
rowIdx => columns.slice(topLeft.colIdx, botRight.colIdx + 1).map(
// Grab the row values and make a text string
col => this.rowGetter(rowIdx)[col.key],
).join('\t'),
).join('\n');
console.debug('text', text);
e.clipboardData.setData('text/plain', text);
}
handlePaste = (e) => {
console.debug('handlePaste Called');
e.preventDefault();
const { topLeft } = this.state;
const newRows = [];
const pasteData = defaultParsePaste(e.clipboardData.getData('text/plain'));
console.debug('pasteData', pasteData);
pasteData.forEach((row) => {
const rowData = {};
// Merge the values from pasting and the keys from the columns
columns.slice(topLeft.colIdx, topLeft.colIdx + row.length)
.forEach((col, j) => {
// Create the key-value pair for the row
rowData[col.key] = row[j];
});
// Push the new row to the changes
newRows.push(rowData);
});
console.debug('newRows', newRows);
this.updateRows(topLeft.rowIdx, newRows);
}
onGridRowsUpdated = ({ fromRow, toRow, updated, action }) => {
console.debug('onGridRowsUpdated!', action);
console.debug('updated', updated);
if (action !== 'COPY_PASTE') {
this.setState((state) => {
const rows = state.rows.slice();
for (let i = fromRow; i <= toRow; i++) {
rows[i] = { ...rows[i], ...updated };
}
return { rows };
});
}
};
setSelection = (args) => {
this.setState({
topLeft: {
rowIdx: args.topLeft.rowIdx,
colIdx: args.topLeft.idx,
},
botRight: {
rowIdx: args.bottomRight.rowIdx,
colIdx: args.bottomRight.idx,
},
});
};
render() {
const { rows } = this.state;
return (
<div>
<ReactDataGrid
columns={columns}
rowGetter={i => rows[i]}
rowsCount={rows.length}
onGridRowsUpdated={this.onGridRowsUpdated}
enableCellSelect
minColumnWidth={40}
cellRangeSelection={{
onComplete: this.setSelection,
}}
/>
</div>
);
}
}
export default MyDataGrid;
@Rohit0510
Copy link

I am using the react data grid version 6.0.10 but still getting the error for the attribute cellRangeSelection and the error is Property 'cellRangeSelection' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes and second issue is when I am trying to copy cells inside the grid .I am not able do it.
Thanks in advance for your help.

@ggkrishkumar
Copy link

Will it work if we are using latest version of react data grid 7.0.0-canary.30 ?

@ecoant
Copy link

ecoant commented Oct 3, 2022

doesn't seem like it, i'm having a hell of a time getting what feels like basic "data grid" functionality on the new 7.0.0-beta-16. I just want to copy and paste to/from like any other application. Not sure why cell selection was removed, or why the onPaste handler only gets called seemingly after something has been copied from INSIDE the grid component. Going beyond beta 16 hilariously and frustratingly screws up the entire grid styling such that it no longer looks anything like a grid component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment