Search code examples
reactjsag-gridcellrenderer

How can I *predictably* mark changed cells in AG-Grid React?


I have a functional component in React that uses the AG-grid component, that looks roughly like this:

import React, { useRef } from 'react'
import { AgGridReact } from 'ag-grid-react'

export default function FormEditor(props) {

  .... code for fetching data etc. goes here ...

  // create ref to be able to call ag-grid.api on our spreadsheet
  const editFormRef = useRef()

  // can we log the row data to the console? Yes!
  function logData() {
    if (!editFormRef.current.api) {
      return
    }
    const rowCount = editFormRef.current.api.getDisplayedRowCount()
    for (let i = 0; i < rowCount; i++) {
      const rowNode = editFormRef.current.api.getDisplayedRowAtIndex(i)
      console.log(`row ${i + 1} -> `, rowNode.data)
      // Perform your logic
    }
  }

  // will the data that's changed be highlighted? Maybe, on the second go...
  function markCellChanged(params) {
    if (!editFormRef.current.api) {
      return
    }
    const row = editFormRef.current.api.getDisplayedRowAtIndex(params.rowIndex)
    console.log('markCellChanged() called ')
    if (params.oldValue !== params.newValue) {
      params.colDef.cellStyle = function(params) {
        return { backgroundColor: '#6fcc44', transparency: 0.5 }
      }
      console.log('Redrawing row ', row)
      editFormRef.current.api.redrawRows({ rowNodes: [row] })
    }
  }

  return (
    <React.Fragment>
      <AgGridReact
        ref={editFormRef}
        rowSelection="multiple"
        columnDefs={columns}
        rowData={rows}
        rowDragManaged={true}
        components={{ editCellEditor: ReviewCellEditor }}
        // editType="fullRow"
        enableFillHandle={true}
      />
      <Button variant="contained" onClick={() => logData()}>
        Log Data
      </Button>
    </React.Fragment>
  )
}

The issue is that it does work, but only on the second go. And it also works, if a cell in that column has already been edited.

This is not the final position I want to be in, as I want to check the data against the original rows supplied, not just the last value changed in a cell. I just thought it was best to start small, and build ;-)

Can anyone explain this behaviour, and let me know where I'm going wrong?


Solution

  • I use ag-grid in Angular, not React, but it seems to me that you shouldn't be changing the columnDef's cellStyle, as that should apply to the entire column.

    If you want to change the style just for the one cell, AFAIK, the proper way to do it is to provide a dictionary of functions for colDef.cellClassRules. The keys are css class names, and the values are functions that take a cell value and return a boolean indicating whether the class should be applied to the cell, as in:

    cellClassRules: {
        // apply green to 2008
        'rag-green-outer': function(params) { return params.value === 2008},
        // apply amber 2004
        'rag-amber-outer': function(params) { return params.value === 2004},
        // apply red to 2000
        'rag-red-outer': function(params) { return params.value === 2000}
    }
    

    See the documentation at https://www.ag-grid.com/javascript-grid-cell-styles/#cell-class-rules