Skip to content

Commit 9cea185

Browse files
authored
Merge pull request #23 from patrick-jones/issue20
Adds arguments for cell coordinates to `valueRenderer` and `dataRenderer`
2 parents a3f0a04 + 4ecc60a commit 9cea185

4 files changed

Lines changed: 49 additions & 25 deletions

File tree

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,18 @@ class App extends React.Component {
7272
### Cells with underlying data
7373

7474
There are two values that each cell shows. The first is via ```valueRenderer``` and the second is via ```dataRenderer```. When a cell is in *edit mode*, it will show the value returned from ```dataRenderer```. It needs to return a string as this value is set in an input field.
75+
Each of these callbacks are passed the cell value as well as the cell's coordinates in the spreadsheet. This allows you to apply formatting logic at rendering time, such as *all cells in the third column should be formatted as dates*.
7576

7677
```jsx
7778
const grid = [
78-
[{value: 5, expr: '1 + 4'}, {value: 6, expr: '6'}],
79-
[{value: 5, expr: '1 + 4'}, {value: 5, expr: '1 + 4'}]
79+
[{value: 5, expr: '1 + 4'}, {value: 6, expr: '6'}, {value: new Date('2008-04-10')}],
80+
[{value: 5, expr: '1 + 4'}, {value: 5, expr: '1 + 4'}, {value: new Date('2004-05-28')}]
8081
]
8182
const onChange = (cell, i, j, newValue) => console.log("New expression :" + newValue)
8283
<ReactDataSheet
8384
data={grid}
84-
valueRenderer={(cell) => cell.value}
85-
dataRenderer={(cell) => cell.expr}
85+
valueRenderer={(cell, i, j) => j == 2 ? cell.value.toDateString() : cell.value}
86+
dataRenderer={(cell, i, j) => j == 2 ? cell.value.toISOString() : cell.expr}
8687
onChange={}
8788
/>
8889
```
@@ -112,8 +113,8 @@ This renders a single cell with the value 5. Once in edit mode, the button will
112113
Option | Type | Description
113114
:--- | :---: | :---
114115
data | Array | Array of rows and each row should contain the cell objects to display
115-
valueRenderer | func | Method to render the value of the cell `function(cell)`. This is visible by default
116-
dataRenderer | func | Method to render the underlying value of the cell `function(cell)`. This data is visible once in edit mode.
116+
valueRenderer | func | Method to render the value of the cell `function(cell, i, j)`. This is visible by default
117+
dataRenderer | func | Method to render the underlying value of the cell `function(cell, i, j)`. This data is visible once in edit mode.
117118
onChange | func | onChange handler: `function(cell, i, j, newValue) {}`
118119
onPaste | func | onPaste handler: `function(array) {}` If set, the function will be called with an array of rows. Each row has an array of objects containing the cell and raw pasted value. If the pasted value cannot be matched with a cell, the cell value will be undefined
119120
onContextMenu | func | Context menu handler : `function(event, cell, i, j)`

lib/DataSheet.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,10 @@ var DataSheet = function (_PureComponent) {
129129

130130
var text = range(start.i, end.i).map(function (i) {
131131
return range(start.j, end.j).map(function (j) {
132-
return data[i][j];
133-
}).map(function (cell) {
134-
var value = dataRenderer ? dataRenderer(cell) : null;
132+
var cell = data[i][j];
133+
var value = dataRenderer ? dataRenderer(cell, i, j) : null;
135134
if (value === '' || value === null || typeof value === 'undefined') {
136-
return valueRenderer(cell);
135+
return valueRenderer(cell, i, j);
137136
}
138137
return value;
139138
}).join('\t');
@@ -389,7 +388,7 @@ var DataSheet = function (_PureComponent) {
389388
editing: isEditing(i, j),
390389
reverting: isReverting(i, j),
391390
colSpan: cell.colSpan,
392-
value: valueRenderer(cell)
391+
value: valueRenderer(cell, i, j)
393392
};
394393
if (cell.component) {
395394
return _react2.default.createElement(_ComponentCell2.default, _extends({}, props, {
@@ -398,7 +397,7 @@ var DataSheet = function (_PureComponent) {
398397
}));
399398
}
400399
return _react2.default.createElement(_DataCell2.default, _extends({}, props, {
401-
data: dataRenderer ? dataRenderer(cell) : null,
400+
data: dataRenderer ? dataRenderer(cell, i, j) : null,
402401
clear: shouldClear(i, j),
403402
rowSpan: cell.rowSpan,
404403
onChange: _this4.onChange,

src/DataSheet.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ export default class DataSheet extends PureComponent {
8282

8383

8484
const text = range(start.i, end.i).map((i) =>
85-
range(start.j, end.j).map(j => data[i][j])
86-
.map(cell => {
87-
let value = dataRenderer ? dataRenderer(cell) : null;
88-
if (value === '' || value === null || typeof(value) === 'undefined') {
89-
return valueRenderer(cell);
90-
}
91-
return value;
92-
}).join('\t')
85+
range(start.j, end.j).map(j => {
86+
const cell = data[i][j];
87+
const value = dataRenderer ? dataRenderer(cell, i, j) : null;
88+
if (value === '' || value === null || typeof(value) === 'undefined') {
89+
return valueRenderer(cell, i, j);
90+
}
91+
return value;
92+
}).join('\t')
9393
).join('\n');
9494
e.clipboardData.setData('text/plain', text);
9595
}
@@ -316,7 +316,7 @@ export default class DataSheet extends PureComponent {
316316
editing: isEditing(i, j),
317317
reverting: isReverting(i, j),
318318
colSpan: cell.colSpan,
319-
value: valueRenderer(cell),
319+
value: valueRenderer(cell, i, j),
320320
};
321321
if (cell.component) {
322322
return <ComponentCell
@@ -327,7 +327,7 @@ export default class DataSheet extends PureComponent {
327327
}
328328
return <DataCell
329329
{...props}
330-
data = {dataRenderer ? dataRenderer(cell) : null}
330+
data = {dataRenderer ? dataRenderer(cell, i, j) : null}
331331
clear = {shouldClear(i, j)}
332332
rowSpan = {cell.rowSpan}
333333
onChange = {this.onChange}

test/Datasheet.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,30 @@ describe('Component', () => {
405405
expect(customWrapper.find('td.cell input').nodes[0].value).toEqual('=+4');
406406
});
407407

408+
it('renders proper elements by column', () => {
409+
const withDates = data.map((row, index) => [{data: new Date('2017-0' + (index + 1) + '-01')}, ...row]);
410+
customWrapper = mount(<DataSheet
411+
data = {withDates}
412+
valueRenderer = {(cell, i, j) => j === 0 ? cell.data.toGMTString() : cell.data}
413+
dataRenderer = {(cell, i, j) => j === 0 ? cell.data.toISOString() : cell.data}
414+
onChange = {(cell, i, j, value) => data[i][j].data = value}
415+
/>);
416+
//expect(wrapper.find('td > span').length).toEqual(6);
417+
expect(customWrapper.find('td > span').nodes.map(n => n.innerHTML)).toEqual(['Sun, 01 Jan 2017 00:00:00 GMT', '4', '2', 'Wed, 01 Feb 2017 00:00:00 GMT', '3', '5']);
418+
});
419+
420+
it('renders data in the input properly if dataRenderer is set by column', () => {
421+
const withDates = data.map((row, index) => [{data: new Date('2017-0' + (index + 1) + '-01')}, ...row]);
422+
customWrapper = mount(<DataSheet
423+
data = {withDates}
424+
valueRenderer = {(cell, i, j) => j === 0 ? cell.data.toGMTString() : cell.data}
425+
dataRenderer = {(cell, i, j) => j === 0 ? cell.data.toISOString() : cell.data}
426+
onChange = {(cell, i, j, value) => data[i][j].data = value}
427+
/>);
428+
customWrapper.find('td').first().simulate('doubleClick');
429+
expect(customWrapper.find('td.cell input').nodes[0].value).toEqual('2017-01-01T00:00:00.000Z');
430+
});
431+
408432
it('renders a component properly', () => {
409433
customWrapper = mount(<DataSheet
410434
data = {[[{component: <div className={'custom-component'}>COMPONENT RENDERED</div>}]]}
@@ -780,16 +804,16 @@ describe('Component', () => {
780804
customWrapper = mount(
781805
<DataSheet
782806
data = {data}
783-
valueRenderer = {(cell) => cell.data}
784-
dataRenderer = {(cell) => "=+" + cell.data}
807+
valueRenderer = {(cell, i, j) => cell.data}
808+
dataRenderer = {(cell, i, j) => "{" + i + "," + j + "}" + cell.data}
785809
onChange = {(cell, i, j, value) => data[i][j].data = value}
786810
/>
787811
);
788812
customWrapper.find('td').at(0).simulate('mouseDown');
789813
customWrapper.find('td').at(3).simulate('mouseOver');
790814

791815
document.dispatchEvent(evt);
792-
expect(copied).toEqual("=+4\t=+2\n=+3\t=+5");
816+
expect(copied).toEqual("{0,0}4\t{0,1}2\n{1,0}3\t{1,1}5");
793817
})
794818

795819
it('copies no data if there isn\'t anything selected', () => {

0 commit comments

Comments
 (0)