React-data-grid: Update value of a cell with javascript function

Created on 3 Feb 2016  路  16Comments  路  Source: adazzle/react-data-grid

Hello,

Is there a function to change a value of the grid directly with javascript?

A bit like when drag directly but by giving value for a cell of a specific row.

Thank you in advance.

Vincent LEVEQUE

Most helpful comment

I found a workaround,
When value of rowsCount prop has changed then it updates rows.
So I temporary change value of rowsCount in this way:

// [...]

  state = {
    refresh: false
  }

  getSize() {
    let count = this._rows.length; // change this line to your app logic

    if (this.state.refresh) {
      count--; // hack for update data-grid
      this.setState({
        refresh: false
      });
    }

    return count;
  }

  refresh() {
    this.setState({
      refresh: true
    });
  }

  render() {
    return (
      <ReactDataGrid
        rowsCount={this.getSize()}
        ...
      />
    );
  }

// [...]

All you need to refresh rows is to call refresh() method, or change state refresh to true: this.setState({ refresh: true }).

How it works:
When refresh state was changed to true then getSize() returns real count of rows + 1 and ReactDataGrid updates the rows,
then it change refresh state to false and after that it calls getSize() in second time and in this time it returns the real count of rows.

All 16 comments

ReactDataGrid is not really responsible for updating your grid data. It will just render what data you pass to it, but provide callbacks as props that you can hook into to modify your data. For example, onCellCopyPaste, onRowSelect,onRowUpdated`

If you want to change he value of a call progamatically, we would recommend updating the rows from whatever data source you are using, and re-render the grid rather than directly modifying the internal data of the grid.

It is not possible to modify a function such handleRowUpdated which update a value in a cell of a row but with an other event, as the execution of a function?

I try to find a solution but I don't know the JSX and therefore can not find...

Thank you

Anybody know can I resolve my problem ?

whats the actual use case? ie what has someone just done, that means you now need to mutate the data? If its something like a mass edit / clicked a button outside the grid, then you should be updating your top level state, ie whatever data structure you expose to rowGetter
If however the user is triggering this by an action in the grid (click, paste, etc) the solution might be different

If you then need to update the data shown in the grid (it wont show until something triggers shouldComponentUpdate ) then you need to force a refresh (or change a prop that has genuinely changed, ie rowCount)
The reason we dont expose a update(row, cell) function is the grid (deliberately) doesnt have access to the full data set - thats what makes it fast and able to handle 1m rows - so if you can only see rows 1-20, but said update(100,2,data) then would not be possible.
Hope that

My use case is to display string length of one of my columns in a next column and auto-update that length. Ideally, while I'm typing.

Task     | 4
Task 1   | 6
New Task | 8

So now I'm trying to find how to refresh veiw after row update.

And I suppose that updating while I'm typing will be more tricky part (is it possible at all?).

P.S. More general case - any formulas, like in Excel.

ah - ok - yes, that is possible, but best achieved in a different way. Some more detail in #138 but the basic gist is that you do this by:

  • in your container, when you first load your data, set the initial value (so your model looks something like: `[{text:'Task',length:4},{text:'Task 1',length:6},)
  • onRowUpdate recompute the length

for changing as you type though, I'd do that in a single editor. Otherwise you'll be re-rendering the row as a user types and have to be careful with DOM element focus position etc. BUt that is possible (just a bit tricky). But something like this should work. and then if you also want a column showing the text length, you can recalcualte the length on your model in onRowUpdated:

getInitialState: () => { textLength: this.props.initialText.length },
onChange: (text) => { this.setState({textLength: text.length}) },
render: () => {
  return (<div><input type="text" initialValue={this.props.initialText} onChange={this.onChange} /> <span>{this.state.textLength}</span></div>)
} 

I tried to make this work with editable example

It doesn't re-render cell when I'm setting it using setState until I click it (as described in #144). Modified versoin of handleRowUpdated:

  handleRowUpdated : function(e){
    //merge updated row with current row and rerender by setting state
    var rows = this.state.rows;
    var updated = e.updated;

    if (e.cellKey == "task") {
      updated.taskLength = updated.task.length;
    }
    Object.assign(rows[e.rowIdx], updated);
    this.setState({rows:rows});
  },

And I have initial length in rows. Gist: https://gist.github.com/denispeplin/c55052e126cc1b29ee51

I created a workaround inspired by #110

this.refs.dataGrid.onSelect({rowIdx: i, idx: j}); //will place grid focus onto specified cell as mentioned by @gtkovas

It will update which row it lands on. However, if you have multiple rows to update, it will only update the last row. I added a 1 millisecond delay between each onSelect call to make the update work fluidly and completely.

322     var self = this;
323     if(indices_to_select.length > 0) {
324       this.setState({rows: rows});
325
326       var current_select_position = $.extend(true, {}, self.refs.dataGrid.state.selected);
327       _.each(indices_to_select, function(index) {
328         // React will not update the rows in the middle if there isn't a slight delay
329         setTimeout(function(){
330           self.refs.dataGrid.onSelect({rowIdx: index, idx: current_select_position.idx});
331         }, 1);
332       });
333       // Allow 1ms delay to return to original position
334       setTimeout(function(){
335         self.refs.dataGrid.onSelect({rowIdx: current_select_position.rowIdx, idx: current_select_po>
336       }, 1);
337     }

Also it's actual for me

This still seems to be an issue.

My use case is that I have two related models in the database backend.

What I want to happen is that when I update a field on the top level model, those changes reflect on other records related to the same top level instance.

So in the handleGridRowsUpdated() when field A updates, I also update field A for other related records.

When I call setState({rows}); the changes aren't reflected in the other records until the user clicks on them.

I have found that this works, but it isn't great in terms of performance:

this.setState({rows: []});
this.setState(rows);

Versions:

[email protected]
[email protected]

I found a workaround,
When value of rowsCount prop has changed then it updates rows.
So I temporary change value of rowsCount in this way:

// [...]

  state = {
    refresh: false
  }

  getSize() {
    let count = this._rows.length; // change this line to your app logic

    if (this.state.refresh) {
      count--; // hack for update data-grid
      this.setState({
        refresh: false
      });
    }

    return count;
  }

  refresh() {
    this.setState({
      refresh: true
    });
  }

  render() {
    return (
      <ReactDataGrid
        rowsCount={this.getSize()}
        ...
      />
    );
  }

// [...]

All you need to refresh rows is to call refresh() method, or change state refresh to true: this.setState({ refresh: true }).

How it works:
When refresh state was changed to true then getSize() returns real count of rows + 1 and ReactDataGrid updates the rows,
then it change refresh state to false and after that it calls getSize() in second time and in this time it returns the real count of rows.

I found a workaround,
When value of rowsCount prop has changed then it updates rows.
So I temporary change value of rowsCount in this way:

// [...]

  state = {
    refresh: false
  }

  getSize() {
    let count = this._rows.length; // change this line to your app logic

    if (this.state.refresh) {
      count++; // hack for update data-grid
      this.setState({
        refresh: false
      });
    }

    return count;
  }

  refresh() {
    this.setState({
      refresh: true
    });
  }

  render() {
    return (
      <ReactDataGrid
        rowsCount={this.getSize()}
        ...
      />
    );
  }

// [...]

All you need to refresh rows is to call refresh() method, or change state refresh to true: this.setState({ refresh: true }).

How it works:
When refresh state was changed to true then getSize() returns real count of rows + 1 and ReactDataGrid updates the rows,
then it change refresh state to false and after that it calls getSize() in second time and in this time it returns the real count of rows.

I want to notice, that better rewrite this getSize function, because there will be a error when updating a grid at the appeal to the array of rows by the nonexistent index
Write as foollows:

getSize() {
    let count = this._rows.length;
    if (this.state.refresh && count > 0) {
      count--; // hack for update data-grid
      this.setState({
        refresh: false
      });
}

I am now using the above, but it feels SUPER dirty!

@DrogoNevets do you have any another solution?

I am now using the above, but it feels SUPER dirty!

if you have another solution, please provide it))

I found a workaround,
When value of rowsCount prop has changed then it updates rows.
So I temporary change value of rowsCount in this way:

// [...]

  state = {
    refresh: false
  }

  getSize() {
    let count = this._rows.length; // change this line to your app logic

    if (this.state.refresh) {
      count++; // hack for update data-grid
      this.setState({
        refresh: false
      });
    }

    return count;
  }

  refresh() {
    this.setState({
      refresh: true
    });
  }

  render() {
    return (
      <ReactDataGrid
        rowsCount={this.getSize()}
        ...
      />
    );
  }

// [...]

All you need to refresh rows is to call refresh() method, or change state refresh to true: this.setState({ refresh: true }).
How it works:
When refresh state was changed to true then getSize() returns real count of rows + 1 and ReactDataGrid updates the rows,
then it change refresh state to false and after that it calls getSize() in second time and in this time it returns the real count of rows.

I want to notice, that better rewrite this getSize function, because there will be a error when updating a grid at the appeal to the array of rows by the nonexistent index
Write as foollows:

getSize() {
    let count = this._rows.length;
    if (this.state.refresh && count > 0) {
      count--; // hack for update data-grid
      this.setState({
        refresh: false
      });
}

This still didn't work me, I'm updating row data which is coming from backend server and calling setState after all rows are updated, I see the data getting updated as expected in the rows passed to the Grid, but unless I click on the rows, the data is not updated. The getSize() explained above didn't work for me.

Was this page helpful?
0 / 5 - 0 ratings