React-data-grid: Grid cannot be editable and sortable/filterable

Created on 26 Feb 2017  路  10Comments  路  Source: adazzle/react-data-grid

WHICH VERSION OF REACT ARE YOU USING?

Officially Supported:
[x] v0.14.x

WHICH BROWSER ARE YOU USING?

Officially Supported:
[ ] IE 9 / IE 10 / IE 11
[ ] Edge
[x] Chrome

I'm submitting a ... (check one with "x")

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/adazzle/react-data-grid/blob/master/CONTRIBUTING.md

Current behavior

If a column is filtered or sorted, and someone tries to edit a cell, the cell does not reflect the edited changes - it goes back to its previous value. If the grid is not filtered or the column is not sorted, then it is editable.

Expected/desired behavior

A cell should be editable both filters and sorting is on. We can sort it manually re:https://github.com/adazzle/react-data-grid/issues/532 if we only have either one of those features, but not both.

Reproduction of the problem
If the current behavior is a bug or you can illustrate your feature request better with an example, please provide the steps to reproduce and if possible a minimal demo of the problem.

  1. Go to demo table http://adazzle.github.io/react-data-grid/examples.html#/filterable-sortable-grid
  2. Make the cells editable
  3. Set a column to be sorted ascending/descending
  4. Edit a cell
  5. The changes to that cell don't persist

What is the expected behavior?

What is the motivation / use case for changing the behavior?

If anyone has any workarounds, I'd be very grateful! 馃檹

Most helpful comment

Thanks @supamanda ! I found a different solution than yours but it still works!

If anyone's interested in the solution:

  • Don't store your rows in this.state.rows, instead, always refer to getRows
    getRows() {
      return Selectors.getRows(this.state);
    }
  • handleGridRowsUpdated , handleFilterChange, handleGridSort, should be the same as the demo example
  • include a this.state.originalRows which is just a copy of your original rows
  • on clearFilters, return this.state.rows to be the original rows
  • Always call this.setState as a callback

All 10 comments

Thanks for putting up this bug - it helped me find a bug in my app :)

The way I worked around it was

  • the handleRowUpdated event passes the rowIdx, key and the updated value, so I find the right row to update by using the rowGetter method
  • the select / deselect row methods pass the entire row data and the row indexes, and I found the best way for me was to add an uneditable (invisible) id key to the data in the table - then store a list of these ids, rather than row index values in the state and in the table rowSelection use selectBy: (keys : ...

Thanks @supamanda ! I found a different solution than yours but it still works!

If anyone's interested in the solution:

  • Don't store your rows in this.state.rows, instead, always refer to getRows
    getRows() {
      return Selectors.getRows(this.state);
    }
  • handleGridRowsUpdated , handleFilterChange, handleGridSort, should be the same as the demo example
  • include a this.state.originalRows which is just a copy of your original rows
  • on clearFilters, return this.state.rows to be the original rows
  • Always call this.setState as a callback

If you are using redux you can dispatch an action and reload the rows. Let's say that the rows in the redux store are the originalRows. Not sure if this is the best way, but it works.

onRowsUpdated({ rowIds, updated } ) {
    dispatch({
        type: UPDATE_ROWS,
        rowIds,
        updated
    });
}

@mi-lee I am using ES6. Can you tell me how to import Selectors?
Presently I am doing

import`{ Toolbar, Data: {Selectors} } from 'react-data-grid-addons'

which is throwing an error saying unexpected token

@beckmeindia is it because of the backtick after import ?

Hey,
No the backtick is a typo in the question posted.
I think the way Data: { Selectors} is written is unusual with respect to ES6 import statement syntax.
Can you suggest an alternative way of writing this part only?

Thanks

@beckmeindia It should work if you've compiled ES6.

Another way is

var ReactDataGrid  = require('react-data-grid-addons')
var Toolbar = ReactDataGrid.Toolbar
var Selectors = ReactDataGrid.Data.Selectors

Thanks.
I think this should work. Will try it!

To build off of @mi-lee's comment, you should reference Selectors.getRows(this.state) in your handleGridRowsUpdated function instead of this.state.rows.slice() _(if you are following this example_: example13-all-features).

When I was making edits on a datagrid with an active filter, this.state.rows.slice()was not returning the id I had anticipated. The fromRow and toRow props were returning a row index relative to the filtered selection, but I was checking this index against the entire data set (instead of the filtered one. Using Selectors.getRows(this.state) solves this issue, because it returns the filtered subset.

My function looks something like this:

handleGridRowsUpdated = ({ fromRow, toRow, updated }) => {
  let rows = Selectors.getRows(this.state)

  for (let i = fromRow; i <= toRow; i++) {
    let rowToUpdate = rows[i]
    let updatedRow = update(rowToUpdate, {$merge: updated})
    rows[i] = updatedRow
  }
  this.setState({ rows })

  // adding my id field to the object 
  updated.id = rows[fromRow].id

  // passing the updated data to my handler function
  this.props.handleUpdate(updated)
}

P.S. the update function I'm using is from immutability-helper (per the guidance of the react docs).

Above solution works but when i remove the filter or sort it only kept the last filter results instead of showing the actual row with edited values.

Here is how i solved the problem (note i had my own Id column to identify the actual row):

for (let i = fromRow; i <= toRow; i++) {
let rowToUpdate = filterSortRow[i];

  let actualRowIndex = this.getActualRowIndexById(rows, rowToUpdate.id);

  //update actual row;
  let actualRowToUpdate = rows[actualRowIndex];
      let actualUpdatedRow = update(actualRowToUpdate, {$merge: updated});
  rows[actualRowIndex] = actualUpdatedRow;

  // update filter row list
      let updatedRow = update(rowToUpdate, {$merge: updated});
      filterSortRow[i] = updatedRow;
}

this.setState({ rows });

};

getActualRowIndexById(list, id){
for (let i = 0; i < list.length; i++) {
let row = list[i];
if(row.id == id){
return i;
}
}
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KalKhera picture KalKhera  路  3Comments

JimLynchCodes picture JimLynchCodes  路  4Comments

GenoD picture GenoD  路  3Comments

soma83 picture soma83  路  4Comments

ryanwtyler picture ryanwtyler  路  3Comments