Skip to content

Commit

Permalink
Add ActiveCell to state and pass to row/cell
Browse files Browse the repository at this point in the history
  • Loading branch information
Steve Baker authored and Steve Baker committed Jul 7, 2014
1 parent 979ef26 commit 15edb33
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 145 deletions.
11 changes: 7 additions & 4 deletions lib/Canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var Canvas = React.createClass({
displayStart: React.PropTypes.number.isRequired,
displayEnd: React.PropTypes.number.isRequired,
length: React.PropTypes.number.isRequired,
ActiveCell: React.PropTypes.object.isRequired,
rows: React.PropTypes.oneOfType([
React.PropTypes.func.isRequired,
React.PropTypes.array.isRequired
Expand All @@ -54,6 +55,8 @@ var Canvas = React.createClass({
key: displayStart + idx,
idx: displayStart + idx,
row: row,
Active: this.props.ActiveCell.row == idx,
ActiveCell: this.props.ActiveCell.cell,
height: rowHeight,
columns: this.props.columns,
cellRenderer: this.props.cellRenderer
Expand Down Expand Up @@ -81,11 +84,11 @@ var Canvas = React.createClass({
},

renderRow: function(props) {
if (React.isValidComponent(this.props.rowRenderer)) {
return cloneWithProps(this.props.rowRenderer, props);
} else {
// if (React.isValidComponent(this.props.rowRenderer)) {
// return cloneWithProps(this.props.rowRenderer(props), props);
// } else {
return this.props.rowRenderer(props);
}
//}
},

renderPlaceholder: function(key, height) {
Expand Down
3 changes: 3 additions & 0 deletions lib/Cell.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ var Cell = React.createClass({
textOverflow: 'ellipsis',
overflow: 'hidden'
};
if(this.props.Active) {
style.backgroundColor='yellow';
}
return (
<div className="react-grid-Cell" style={style}>
{this.props.renderer({
Expand Down
1 change: 1 addition & 0 deletions lib/Grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ var Grid = React.createClass({
regularColumns={this.state.regularColumns}
totalWidth={this.DOMMetrics.gridWidth()}
onViewportScroll={this.onViewportScroll}
ActiveCell={this.props.ActiveCell}
/>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions lib/Row.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ var Row = React.createClass({
height: this.props.height,
overflow: 'hidden'
};

var children;

if (React.isValidComponent(this.props.row)) {
children = this.props.row;
} else {
children = this.props.columns.map((column, idx) => Cell({
key: idx,
row: this.props.row.key || null,
row: this.props.row.key || null,
Active: this.props.Active && this.props.ActiveCell === (column.idx != null ? column.idx : idx),
value: this.props.row[column.key || idx],
column: column,
height: this.props.height,
Expand Down
4 changes: 3 additions & 1 deletion lib/Viewport.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ var Viewport = React.createClass({
rows={this.props.rows}
columns={this.props.lockedColumns.columns}
rowRenderer={this.props.rowRenderer}
ActiveCell={this.props.ActiveCell}

visibleStart={this.state.visibleStart}
visibleEnd={this.state.visibleEnd}
Expand Down Expand Up @@ -241,7 +242,8 @@ var Viewport = React.createClass({
rows={this.props.rows}
columns={this.props.regularColumns.columns}
rowRenderer={this.props.rowRenderer}

ActiveCell={this.props.ActiveCell}

visibleStart={this.state.visibleStart}
visibleEnd={this.state.visibleEnd}
displayStart={this.state.displayStart}
Expand Down
259 changes: 121 additions & 138 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,155 +7,138 @@ var React = require('React');

module.exports = Grid;

var editedEvent = function(cell) {
editRow(cell.props.row);
}
var editRow = function(idx) {
var item = data[idx];
if(item) {
item.editing = !item.editing;
item['supplier'].editing = !item['supplier'].editing;
renderGrid();
}
var data = [];
for (var i = 0; i < 2000; i++) {
data.push({
'key': i,
'supplier':{'value':'Supplier ' + i, 'editing':true},
'format': 'fmt ' + i,
'start':'start',
'end':'end',
'price':i });
};


function rows(start, end) {
return data.slice(start, end);
}
var RowEditControl = React.createClass({
handleChange: function(ev) {
editRow(ev.currentTarget.value);

var columns = [

{
idx: 0,
name: 'Supplier',
key: 'supplier',
width: 300,
locked: true,
renderer: EditableCell,
},
{
idx: 1,
name: 'Format',
key: 'format',
width: 350,
},
{
idx: 2,
name: 'Start',
key: 'start',
width: 250,
},
{
idx: 3,
name: 'End',
key: 'end',
width: 250,
},
{
idx: 4,
name: 'Cost',
key: 'cost',
width: 200,
}
];

var ExcelGrid = React.createClass({
getInitialState: function() {
return {
ActiveCell:{ row:2,cell:2 },
NoRows:data.length,
rowHeight:40
};
},
render: function() {
return (
<input type="text" onChange={this.handleChange} defaultValue="1"/>)
}});
React.renderComponent(RowEditControl(), document.getElementById('edit-test'));

var EditableCell = React.createClass({
//GOT IT
// was setting editing on the row, NOT the value that gets passed to the editor
//with that, this all works (no state needed...)
//still a fair few hacks (passing row into the cell is probably the biggest!)
//so need to think out if there is a way round that
//and the hacky en=vent > closure callout
//maybe better to have a row > cell onChange callback to then update props and pass thenm up to the grid
//or see if we can use the overridable rowRenderer to add this event in

//using state for editing is fine, BUT as soon as the component is destroyed, we lose state
//in pratice that means that if we scroll, we lose our editing state
//using a key helps, but components still get garbaged, quite quickly, so we have broken ui
<div onClick={this.handleGridClick}
onDoubleClick={this.handleGridDoubleClick}
>
<Grid
columns={columns}
rows={rows}
ActiveCell={this.state.ActiveCell}

length={this.state.NoRows}
rowHeight={this.state.rowHeight}
/>
</div>
);

//but doing this via callbacks, and probably decent implementations of componentShouldUpdate, means passing them around:
//grid < row < cell < renderer(here)
//doesnt really feel right for row or cell to know about that..
//so played with using .props.editing
//and then calling out (via a closure, as I was being hacky) to set the grid data for the row
//could do it properly with event bus?
//and re-render. but that wasnt actually rendering... ugh
//not sure if mixins could be useful here?

//or is the right approach to just have
//<Row onRowChange="callback" />
//<Cell onCellChange="callback" />
//<CellRenderer onChange="callback" />
getInitialState: function() {
return {editing: this.props.editing};
},
render: function() {
var key="c-" + this.props.row + "-" + this.props.key;
if(this.props.value.editing) {
return (
<div key={key} onClick={this.handleClick}>
<input type="text" value={this.props.value.value}/> key:'{key}'
</div>)
}
return (
<div key={key} onClick={this.handleClick}>
{this.props.value.value} key:'{key}'
</div>
)
},
handleClick: function(ev) {
this.setState({editing:!this.state.editing});
editRow(this.props.row);
},
handleGridClick: function(ev) {

},
handleGridDoubleClick: function(ev) {

},
componentDidMount: function() {
//handling outside of react
//reacts keyup is only bound, from what I can tell, if you are focussed on a user input
//generally, that makes sense (and guess may be more performant)
//but for our purpose see https://github.com/facebook/react/issues/1795
window.addEventListener('keyup', this.handleKeyUp);
},
componentWillUnmount: function() {
window.removeEventListener('keyup', this.handleKeyUp);
},
handleKeyUp: function(ev) {
var active = this.state.ActiveCell;
var change = false;
if(ev.keyCode == 38) { //UP
active.row -= 1;
change=true;
}
if(ev.keyCode == 40) { //DOWN
active.row += 1;
change=true;
}
if(ev.keyCode == 37) { //LEFT
active.cell -= 1;
change=true;
}
if(ev.keyCode == 39) { //RIGHT
active.cell += 1;
change=true;
}
if(change) {
//sense check bounds
if(active.cell < 0) {active.cell = columns.length;}
if(active.cell >= columns.length) {active.cell = 0;}
if(active.row < 0) {active.row = data.length;}
if(active.row >= data.length) {active.row = 0;}
this.setState({ActiveCell : active});
}
}
});

var data = [];
for (var i = 0; i < 2000; i++) {
data.push({
'key': i,
'supplier':{'value':'Supplier ' + i, 'editing':true},
'format': 'fmt ' + i,
'start':'start',
'end':'end',
'price':i });
};



// var Cell = require('./Cell');

// var editableRow = React.createClass({
// handleClick: function(cell) {

// },
// render: function() {
// var children = this.props.columns.map((column, idx) => Cell({
// key: idx,
// rowKey: column.key || idx,
// value: this.props.row[column.key || idx],
// column: column,
// height: this.props.height,
// renderer: column.renderer || this.props.cellRenderer,
// onClick: handleClick
// }));

// return <div>{children}</div>;
// },
// });
function rows(start, end) {
return data.slice(start, end);//.map((row, idx) => editableRow({row: row, columns: columns}));
}

var columns = [

{
name: 'Supplier',
key: 'supplier',
width: 300,
locked: true,
renderer: EditableCell,
},
{
name: 'Format',
key: 'format',
width: 350,
},
{
name: 'Start',
key: 'start',
width: 250,
},
{
name: 'End',
key: 'end',
width: 250,
},
{
name: 'Cost',
key: 'cost',
width: 200,
}
];

var renderGrid = function() {
React.renderComponent(
Grid({
columns: columns,
length: 10000,
rows: rows,
rowHeight: 40
}), document.getElementById('example'));
var grid = ExcelGrid({});
React.renderComponent(grid,
document.getElementById('example'));
};
renderGrid();

//force a global react object, for chrome dev tools if nothing else
window.React = window.React || React;



0 comments on commit 15edb33

Please sign in to comment.