Created
November 29, 2018 15:37
-
-
Save ZackKnopp/40fc0691feb03f0fba3e25e7353b73ae to your computer and use it in GitHub Desktop.
Copy paste selection range for react-data-grid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Fix for copy cell in react-data-grid showing up | |
.react-grid-cell-copied { | |
display: none; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
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
Will it work if we are using latest version of react data grid 7.0.0-canary.30 ?